diff --git a/frontend/frontend/package.json b/frontend/frontend/package.json index 6dcd561d..26d92dd6 100644 --- a/frontend/frontend/package.json +++ b/frontend/frontend/package.json @@ -59,11 +59,8 @@ }, "scripts": { "setup-trends": "cp ./public/trends.html ./public/index.html", - "setup-wrapped": "cp ./public/wrapped.html ./public/index.html", "start-trends": "yarn setup-trends && REACT_APP_MODE=trends craco start", - "start-wrapped": "yarn setup-wrapped && REACT_APP_MODE=wrapped PORT=3001 craco start", "build-trends": "yarn setup-trends && REACT_APP_MODE=trends craco build", - "build-wrapped": "yarn setup-wrapped && REACT_APP_MODE=wrapped craco build", "test": "craco test", "eject": "react-scripts eject" }, diff --git a/frontend/frontend/public/preview_wrapped.png b/frontend/frontend/public/preview_wrapped.png deleted file mode 100644 index 68405a34..00000000 Binary files a/frontend/frontend/public/preview_wrapped.png and /dev/null differ diff --git a/frontend/frontend/public/wrapped.html b/frontend/frontend/public/wrapped.html deleted file mode 100644 index 41a406ac..00000000 --- a/frontend/frontend/public/wrapped.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GitHub Wrapped - - - -
- - diff --git a/frontend/frontend/src/api/index.js b/frontend/frontend/src/api/index.js index 8e99eb82..acb34390 100644 --- a/frontend/frontend/src/api/index.js +++ b/frontend/frontend/src/api/index.js @@ -5,6 +5,4 @@ import { deleteAccount, } from './user'; -import { getWrapped } from './wrapped'; - -export { setUserKey, authenticate, getUserMetadata, deleteAccount, getWrapped }; +export { setUserKey, authenticate, getUserMetadata, deleteAccount }; diff --git a/frontend/frontend/src/api/wrapped.js b/frontend/frontend/src/api/wrapped.js deleted file mode 100644 index 58d21bd6..00000000 --- a/frontend/frontend/src/api/wrapped.js +++ /dev/null @@ -1,29 +0,0 @@ -/* eslint-disable no-return-await */ - -import axios from 'axios'; - -import { BACKEND_URL } from '../constants'; - -const URL_PREFIX = `${BACKEND_URL}/wrapped`; - -const getValidUser = async (userId) => { - try { - const fullUrl = `${URL_PREFIX}/valid/${userId}`; - const result = await axios.get(fullUrl); - return result.data.data; - } catch (error) { - return null; - } -}; - -const getWrapped = async (userId, year) => { - try { - const fullUrl = `${URL_PREFIX}/${userId}?year=${year}`; - const result = await axios.get(fullUrl); - return result.data.data; - } catch (error) { - return null; - } -}; - -export { getWrapped, getValidUser }; diff --git a/frontend/frontend/src/assets/wrapped1.png b/frontend/frontend/src/assets/wrapped1.png deleted file mode 100644 index f24a1900..00000000 Binary files a/frontend/frontend/src/assets/wrapped1.png and /dev/null differ diff --git a/frontend/frontend/src/assets/wrapped2.png b/frontend/frontend/src/assets/wrapped2.png deleted file mode 100644 index 80eb9f94..00000000 Binary files a/frontend/frontend/src/assets/wrapped2.png and /dev/null differ diff --git a/frontend/frontend/src/assets/wrapped3.png b/frontend/frontend/src/assets/wrapped3.png deleted file mode 100644 index 1fe18597..00000000 Binary files a/frontend/frontend/src/assets/wrapped3.png and /dev/null differ diff --git a/frontend/frontend/src/components/Wrapped/Organization.js b/frontend/frontend/src/components/Wrapped/Organization.js deleted file mode 100644 index b41141c0..00000000 --- a/frontend/frontend/src/components/Wrapped/Organization.js +++ /dev/null @@ -1,59 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { classnames } from '../../utils'; - -const WrappedSection = (props) => { - return ( -
- {props.useTitle && ( -

{props.title}

- )} - {props.children} -
- ); -}; - -WrappedSection.propTypes = { - useTitle: PropTypes.bool, - title: PropTypes.string, - children: PropTypes.node.isRequired, -}; - -WrappedSection.defaultProps = { - useTitle: true, - title: '', -}; - -const WrappedCard = (props) => { - return ( -
-
- {props.children} -
-
- ); -}; - -WrappedCard.propTypes = { - children: PropTypes.node.isRequired, - className: PropTypes.string, - onMouseOver: PropTypes.func, - onMouseOut: PropTypes.func, -}; - -WrappedCard.defaultProps = { - className: '', - onMouseOver: () => {}, - onMouseOut: () => {}, -}; - -export { WrappedSection, WrappedCard }; diff --git a/frontend/frontend/src/components/Wrapped/Specifics/Bar.js b/frontend/frontend/src/components/Wrapped/Specifics/Bar.js deleted file mode 100644 index 0f25ac7e..00000000 --- a/frontend/frontend/src/components/Wrapped/Specifics/Bar.js +++ /dev/null @@ -1,145 +0,0 @@ -import React, { useState } from 'react'; -import PropTypes from 'prop-types'; - -import { WrappedCard } from '../Organization'; -import { BarGraph } from '../Templates'; - -const monthNames = [ - 'Jan', - 'Feb', - 'March', - 'April', - 'May', - 'June', - 'July', - 'Aug', - 'Sep', - 'Oct', - 'Nov', - 'Dec', -]; - -const dayNames = [ - 'Sunday', - 'Monday', - 'Tuesday', - 'Wednesday', - 'Thursday', - 'Friday', - 'Saturday', -]; - -const BarMonth = ({ data, downloadLoading }) => { - const newData = data?.month_data?.months || []; - - // eslint-disable-next-line no-unused-vars - const [displayContribs, setDisplayContribs] = useState(true); - - return ( -
- -
-
-

Contributions by Month

-

- {displayContribs ? 'By Contribution Count' : 'By LOC Changed'} -

-
- {!downloadLoading && ( -
- -
- )} -
- {displayContribs ? ( - d.contribs} - legendText="Contributions" - /> - ) : ( - d.formatted_loc_changed.split(' ')[0]} - legendText="LOC Changed" - /> - )} -
-
- ); -}; - -BarMonth.propTypes = { - data: PropTypes.object.isRequired, - downloadLoading: PropTypes.bool.isRequired, -}; - -const BarDay = ({ data, downloadLoading }) => { - const newData = data?.day_data?.days || []; - - const [displayContribs, setDisplayContribs] = useState(true); - - return ( -
- -
-
-

Contributions by Day

-

- {displayContribs ? 'By Contribution Count' : 'By LOC Changed'} -

-
- {!downloadLoading && ( -
- -
- )} -
- {displayContribs ? ( - d.contribs} - legendText="Contributions" - /> - ) : ( - d.formatted_loc_changed.split(' ')[0]} - legendText="LOC Changed" - /> - )} -
-
- ); -}; - -BarDay.propTypes = { - data: PropTypes.object.isRequired, - downloadLoading: PropTypes.bool.isRequired, -}; - -export { BarMonth, BarDay }; diff --git a/frontend/frontend/src/components/Wrapped/Specifics/Calendar.js b/frontend/frontend/src/components/Wrapped/Specifics/Calendar.js deleted file mode 100644 index babe1874..00000000 --- a/frontend/frontend/src/components/Wrapped/Specifics/Calendar.js +++ /dev/null @@ -1,125 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { ResponsiveCalendar } from '@nivo/calendar'; - -import { Input } from '../../Generic'; -import { theme, scale } from '../Templates/theme'; -import { WrappedCard } from '../Organization'; - -const Calendar = ({ - data, - startDate, - endDate, - highlightDays, - highlightColors, - downloadLoading, -}) => { - const newData = data?.calendar_data?.days || []; - - const valueOptions = [ - { value: 'contribs', label: 'Contributions', disabled: false }, - { value: 'commits', label: 'Commits', disabled: false }, - { value: 'issues', label: 'Issues', disabled: false }, - { value: 'prs', label: 'Pull Requests', disabled: false }, - { value: 'reviews', label: 'Reviews', disabled: false }, - ]; - - const [value, setValue] = React.useState(valueOptions[0]); - - const numEvents = Array.isArray(newData) - ? newData.reduce((acc, x) => acc + x[value.value], 0) - : 0; - - let c = 0; - const max = Math.max(...newData.map((x) => x[value.value])); - const quantiles = [ - Math.floor(max * 0.25), - Math.floor(max * 0.5), - Math.floor(max * 0.75), - max, - ]; - - const colorScaleFn = (x) => { - const count = (c % 365) + 1; - c += 1; - - const myColorScale = highlightDays.includes(count) - ? highlightColors - : scale; - - if (x === 0) { - return myColorScale[0]; - } - if (x <= quantiles[0]) { - return myColorScale[1]; - } - if (x <= quantiles[1]) { - return myColorScale[2]; - } - if (x <= quantiles[2]) { - return myColorScale[3]; - } - return myColorScale[4]; - }; - - return ( -
- -
-

- Contribution Calendar -

- {!downloadLoading && ( - - )} -
-
-

{`${numEvents} ${value.label}`}

- {Array.isArray(newData) && newData.length > 0 ? ( - ({ - day: item.day, - value: item[value.value], - }))} - from={startDate} - to={endDate} - emptyColor="#EBEDF0" - colors={['#9BE9A8', '#40C463', '#30A14E', '#216E39']} - margin={{ top: 10, right: 0, bottom: 0, left: 0 }} - monthBorderColor="#ffffff" - dayBorderWidth={2} - dayBorderColor="#ffffff" - colorScale={colorScaleFn} - /> - ) : ( -
- No data to show -
- )} -
-
-
- ); -}; - -Calendar.propTypes = { - data: PropTypes.object.isRequired, - startDate: PropTypes.string.isRequired, - endDate: PropTypes.string.isRequired, - highlightDays: PropTypes.arrayOf(PropTypes.number), - highlightColors: PropTypes.arrayOf(PropTypes.string).isRequired, - downloadLoading: PropTypes.bool.isRequired, -}; - -Calendar.defaultProps = { - highlightDays: [], -}; - -export default Calendar; diff --git a/frontend/frontend/src/components/Wrapped/Specifics/Numeric.js b/frontend/frontend/src/components/Wrapped/Specifics/Numeric.js deleted file mode 100644 index f7cb30b9..00000000 --- a/frontend/frontend/src/components/Wrapped/Specifics/Numeric.js +++ /dev/null @@ -1,109 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { WrappedCard } from '../Organization'; - -const numericPropTypes = { - num: PropTypes.any, - label: PropTypes.string.isRequired, -}; - -const numericDefaultProps = { - num: 'N/A', -}; - -const NumericPlusLOC = ({ num, label }) => { - return ( - -

{`+${num}`}

-

{label}

-
- ); -}; - -NumericPlusLOC.propTypes = numericPropTypes; -NumericPlusLOC.defaultProps = numericDefaultProps; - -const NumericMinusLOC = ({ num, label }) => { - return ( - -

{`-${num}`}

-

{label}

-
- ); -}; - -NumericMinusLOC.propTypes = numericPropTypes; -NumericMinusLOC.defaultProps = numericDefaultProps; - -const NumericBothLOC = ({ num1, num2, label }) => { - return ( - -
-

- {num1} -

-

/

-

- {num2} -

-
-

{label}

-
- ); -}; - -NumericBothLOC.propTypes = { - num1: PropTypes.any, - num2: PropTypes.any, - label: PropTypes.string.isRequired, -}; - -NumericBothLOC.defaultProps = { - num1: 'N/A', - num2: 'N/A', -}; - -const NumericBestDay = ({ - num, - date, - label, - className, - onMouseOver, - onMouseOut, -}) => { - return ( - -
-

- {num} Contributions -

-

- on {date} -

-
-

{label}

-
- ); -}; - -NumericBestDay.propTypes = { - num: PropTypes.number.isRequired, - date: PropTypes.string.isRequired, - label: PropTypes.string.isRequired, - className: PropTypes.string, - onMouseOver: PropTypes.func, - onMouseOut: PropTypes.func, -}; - -NumericBestDay.defaultProps = { - className: '', - onMouseOver: () => {}, - onMouseOut: () => {}, -}; - -export { NumericPlusLOC, NumericMinusLOC, NumericBothLOC, NumericBestDay }; diff --git a/frontend/frontend/src/components/Wrapped/Specifics/Pie.js b/frontend/frontend/src/components/Wrapped/Specifics/Pie.js deleted file mode 100644 index cd727abb..00000000 --- a/frontend/frontend/src/components/Wrapped/Specifics/Pie.js +++ /dev/null @@ -1,98 +0,0 @@ -/* eslint-disable react/jsx-curly-newline */ - -import React from 'react'; -import PropTypes from 'prop-types'; - -import { PieChart } from '../Templates'; -import { WrappedCard } from '../Organization'; - -const PieLangs = ({ data, downloadLoading }) => { - const [useLOCAdded, setUseLOCAdded] = React.useState(false); - - const metric = useLOCAdded ? 'added' : 'changed'; - const newData = data?.lang_data?.[`langs_${metric}`] || []; - - return ( -
- -
-
-

Most Used Languages

-

{useLOCAdded ? 'By LOC Added' : 'By LOC Changed'}

-
- {!downloadLoading && ( -
- -
- )} -
- e.data.label} - getFormattedValue={(e) => e.formatted_value} - colors={{ datum: 'data.color' }} - /> -
-
- ); -}; - -PieLangs.propTypes = { - data: PropTypes.object.isRequired, - downloadLoading: PropTypes.bool.isRequired, -}; - -const PieRepos = ({ data, downloadLoading }) => { - const [useLOCAdded, setUseLOCAdded] = React.useState(false); - - const metric = useLOCAdded ? 'added' : 'changed'; - const newData = data?.repo_data?.[`repos_${metric}`] || []; - - return ( -
- -
-
-

Most Active Repositories

-

{useLOCAdded ? 'By LOC Added' : 'By LOC Changed'}

-
- {!downloadLoading && ( -
- -
- )} -
- { - if (label && label.includes('/')) { - return label.split('/')[1].replace('repository', 'private'); - } - return label; - }} - getFormattedValue={(e) => e.formatted_value} - colors={{ scheme: 'category10' }} - /> -
-
- ); -}; - -PieRepos.propTypes = { - data: PropTypes.object.isRequired, - downloadLoading: PropTypes.bool.isRequired, -}; - -export { PieLangs, PieRepos }; diff --git a/frontend/frontend/src/components/Wrapped/Specifics/Radar.js b/frontend/frontend/src/components/Wrapped/Specifics/Radar.js deleted file mode 100644 index 5181bdbb..00000000 --- a/frontend/frontend/src/components/Wrapped/Specifics/Radar.js +++ /dev/null @@ -1,59 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { ResponsiveRadar } from '@nivo/radar'; - -import { WrappedCard } from '../Organization'; - -// eslint-disable-next-line no-unused-vars -const Radar = ({ data }) => { - const commits = data?.numeric_data?.contribs?.commits || 0; - const issues = data?.numeric_data?.contribs?.issues || 0; - const prs = data?.numeric_data?.contribs?.prs || 0; - const reviews = data?.numeric_data?.contribs?.reviews || 0; - - const tempData = [ - { - name: 'Commits', - count: Math.log(1 + commits), - }, - { - name: 'Issues', - count: Math.log(1 + issues), - }, - { - name: 'Pull Requests', - count: Math.log(1 + prs), - }, - { - name: 'Reviews', - count: Math.log(1 + reviews), - }, - ]; - - return ( -
- -

Contributions by Type

-

Log Scale

- Math.round(Math.exp(d) - 1)} - margin={{ top: 30, right: 50, bottom: 30, left: 60 }} - dotSize={10} - colors={{ scheme: 'category10' }} - blendMode="multiply" - motionConfig="wobbly" - /> -
-
- ); -}; - -Radar.propTypes = { - data: PropTypes.object.isRequired, -}; - -export default Radar; diff --git a/frontend/frontend/src/components/Wrapped/Specifics/Swarm.js b/frontend/frontend/src/components/Wrapped/Specifics/Swarm.js deleted file mode 100644 index 8979419c..00000000 --- a/frontend/frontend/src/components/Wrapped/Specifics/Swarm.js +++ /dev/null @@ -1,49 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { SwarmPlot } from '../Templates'; - -const formatYAxis = (value) => { - if (value === 3600 * 12) { - return 'Noon'; - } - if (value === 3600 * 24) { - return 'Midnight'; - } - let hours = Math.floor(value / 3600); - const suffix = hours % 24 >= 12 ? 'PM' : 'AM'; - hours = hours % 12 === 0 ? 12 : hours % 12; - const minutes = String(Math.floor((value % 3600) / 60 / 10) * 10); - const displayHour = String(hours).padStart(2, '0'); - const displayMinute = String(minutes).padStart(2, '0'); - return `${displayHour}:${displayMinute} ${suffix}`; -}; - -const SwarmDay = ({ data }) => { - let newData = data?.timestamp_data?.contribs || []; - newData = newData.map((d, i) => { - return { - ...d, - groupById: 0, - id: i, - }; - }); - - return ( - ''} - formatYAxis={formatYAxis} - /> - ); -}; - -SwarmDay.propTypes = { - data: PropTypes.object.isRequired, -}; - -export { SwarmDay }; diff --git a/frontend/frontend/src/components/Wrapped/Specifics/index.js b/frontend/frontend/src/components/Wrapped/Specifics/index.js deleted file mode 100644 index ce3a2a99..00000000 --- a/frontend/frontend/src/components/Wrapped/Specifics/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import Calendar from './Calendar'; - -export * from './Bar'; -export * from './Numeric'; -export * from './Pie'; -export * from './Swarm'; -export { Calendar }; diff --git a/frontend/frontend/src/components/Wrapped/Templates/Bar.js b/frontend/frontend/src/components/Wrapped/Templates/Bar.js deleted file mode 100644 index 34a36261..00000000 --- a/frontend/frontend/src/components/Wrapped/Templates/Bar.js +++ /dev/null @@ -1,80 +0,0 @@ -/* eslint-disable react/jsx-curly-newline */ - -import React from 'react'; -import PropTypes from 'prop-types'; - -import { ResponsiveBar } from '@nivo/bar'; - -import { theme } from './theme'; - -const BarGraph = ({ data, labels, xTitle, type, getLabel, legendText }) => { - const maxData = Math.max(...data.map((d) => d[type])); - const minData = Math.min( - ...data.filter((d) => d.index < 11).map((d) => d[type]), - ); - - const getColor = (d) => { - // eslint-disable-next-line no-nested-ternary - return d.value === maxData - ? '#2BA02C' - : d.value === minData - ? '#D62728' - : '#468CBF'; - }; - - if (!(Array.isArray(data) && data.length > 0)) { - return ( -
- No data to show -
- ); - } - - return ( - labels[value], - }} - axisLeft={{ - tickSize: 5, - tickPadding: 5, - tickRotation: 0, - legend: legendText, - legendPosition: 'middle', - legendOffset: -60, - }} - label={(d) => getLabel(d.data)} - labelSkipWidth={12} - labelSkipHeight={12} - labelTextColor="#fff" - tooltip={() => null} - /> - ); -}; - -BarGraph.propTypes = { - data: PropTypes.array.isRequired, - labels: PropTypes.array.isRequired, - xTitle: PropTypes.string.isRequired, - type: PropTypes.string.isRequired, - getLabel: PropTypes.func.isRequired, - legendText: PropTypes.string.isRequired, -}; - -export default BarGraph; diff --git a/frontend/frontend/src/components/Wrapped/Templates/Numeric.js b/frontend/frontend/src/components/Wrapped/Templates/Numeric.js deleted file mode 100644 index 1b09d6d6..00000000 --- a/frontend/frontend/src/components/Wrapped/Templates/Numeric.js +++ /dev/null @@ -1,102 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { ResponsivePie } from '@nivo/pie'; - -import { WrappedCard } from '../Organization'; - -const Numeric = ({ num, label }) => { - return ( - -

- {num || 'N/A'} -

-

{label}

-
- ); -}; - -Numeric.propTypes = { - num: PropTypes.any, - label: PropTypes.string.isRequired, -}; - -Numeric.defaultProps = { - num: 'N/A', -}; - -const NumericOutOf = ({ - num, - outOf, - format, - label, - color, - className, - onMouseOver, - onMouseOut, -}) => { - // eslint-disable-next-line react/prop-types - const CenteredMetric = ({ dataWithArc, centerX, centerY }) => { - let total = 0; - // eslint-disable-next-line react/prop-types - dataWithArc.forEach((datum) => { - total += datum.id === '1' ? datum.value : 0; - }); - - return ( - - {format(total)} - - ); - }; - return ( - -
- null} - /> -
-

{label}

-
- ); -}; - -NumericOutOf.propTypes = { - num: PropTypes.number.isRequired, - outOf: PropTypes.number.isRequired, - format: PropTypes.func, - label: PropTypes.string.isRequired, - color: PropTypes.string, - className: PropTypes.string, - onMouseOver: PropTypes.func, - onMouseOut: PropTypes.func, -}; - -NumericOutOf.defaultProps = { - format: (x) => x, - color: '#30A14E', - className: '', - onMouseOver: () => {}, - onMouseOut: () => {}, -}; - -export { Numeric, NumericOutOf }; diff --git a/frontend/frontend/src/components/Wrapped/Templates/Pie.js b/frontend/frontend/src/components/Wrapped/Templates/Pie.js deleted file mode 100644 index b6d89193..00000000 --- a/frontend/frontend/src/components/Wrapped/Templates/Pie.js +++ /dev/null @@ -1,68 +0,0 @@ -/* eslint-disable react/jsx-curly-newline */ - -import React from 'react'; -import PropTypes from 'prop-types'; - -import { ResponsivePie } from '@nivo/pie'; - -import { theme } from './theme'; - -const PieChart = ({ data, getArcLinkLabel, getFormattedValue, colors }) => { - if (!(Array.isArray(data) && data.length > 0)) { - return ( -
- No data to show -
- ); - } - return ( - getArcLinkLabel(e)} - arcLinkLabelsSkipAngle={45} - arcLinkLabelsTextOffset={0} - arcLinkLabelsTextColor={{ from: 'color' }} - arcLinkLabelsDiagonalLength={5} - arcLinkLabelsStraightLength={5} - arcLinkLabelsThickness={0} - // Arc Label Settings - arcLabel={(e) => getFormattedValue(e.data)} - arcLabelsSkipAngle={45} - arcLabelsTextColor="#fff" - // Tooltip - tooltip={({ datum }) => ( -
- {datum.label} - {`: ${getFormattedValue(datum.data)}`} -
- )} - colors={colors} - /> - ); -}; - -PieChart.propTypes = { - data: PropTypes.array.isRequired, - getArcLinkLabel: PropTypes.func.isRequired, - getFormattedValue: PropTypes.func.isRequired, - colors: PropTypes.any.isRequired, -}; - -export default PieChart; diff --git a/frontend/frontend/src/components/Wrapped/Templates/Swarm.js b/frontend/frontend/src/components/Wrapped/Templates/Swarm.js deleted file mode 100644 index 7ce57318..00000000 --- a/frontend/frontend/src/components/Wrapped/Templates/Swarm.js +++ /dev/null @@ -1,94 +0,0 @@ -/* eslint-disable react/prop-types */ -/* eslint-disable react/jsx-curly-newline */ - -import React from 'react'; -import PropTypes from 'prop-types'; - -import { ResponsiveSwarmPlot } from '@nivo/swarmplot'; - -import { theme } from './theme'; -import { WrappedCard } from '../Organization'; - -const MemoizedResponsiveSwarmPlot = React.memo( - ResponsiveSwarmPlot, - (prevProps, nextProps) => prevProps.data?.length === nextProps.data?.length, -); - -const SwarmPlot = ({ - header, - data, - groupBy, - groups, - legend, - formatXAxis, - formatYAxis, -}) => { - const tickValues = [0, 1, 2, 3, 4, 5, 6, 7, 8].map((i) => 10800 * i); - - return ( -
- -

{header}

-

{`${data.length} Sampled Contributions, Eastern Time`}

- {Array.isArray(data) && data.length > 0 ? ( - formatXAxis(value), - }} - axisLeft={{ - orient: 'left', - tickSize: 10, - tickPadding: 5, - tickRotation: 0, - legend: 'Time of Day', - legendPosition: 'middle', - legendOffset: -86, - tickValues, - format: (value) => formatYAxis(value), - }} - /> - ) : ( -
- No data to show -
- )} -
-
- ); -}; - -SwarmPlot.propTypes = { - header: PropTypes.string.isRequired, - data: PropTypes.array.isRequired, - groupBy: PropTypes.string.isRequired, - groups: PropTypes.array.isRequired, - legend: PropTypes.string.isRequired, - formatXAxis: PropTypes.func.isRequired, - formatYAxis: PropTypes.func.isRequired, -}; - -export default SwarmPlot; diff --git a/frontend/frontend/src/components/Wrapped/Templates/index.js b/frontend/frontend/src/components/Wrapped/Templates/index.js deleted file mode 100644 index 7c2f9ac7..00000000 --- a/frontend/frontend/src/components/Wrapped/Templates/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import BarGraph from './Bar'; -import PieChart from './Pie'; -import SwarmPlot from './Swarm'; - -export * from './Numeric'; -export * from './theme'; -export { BarGraph, PieChart, SwarmPlot }; diff --git a/frontend/frontend/src/components/Wrapped/Templates/theme.js b/frontend/frontend/src/components/Wrapped/Templates/theme.js deleted file mode 100644 index dd542730..00000000 --- a/frontend/frontend/src/components/Wrapped/Templates/theme.js +++ /dev/null @@ -1,20 +0,0 @@ -export const theme = { - fontSize: '12px', - fontFamily: 'Segoe UI', -}; - -export const scale = ['#EBEDF0', '#9BE9A8', '#40C463', '#30A14E', '#216E39']; -export const hoverScale = [ - '#A6C9F5', - '#7EC7D1', - '#50B5AF', - '#48A3A4', - '#418A9A', -]; -export const singleHoverScale = [ - '#468CBF', - '#468CBF', - '#468CBF', - '#468CBF', - '#468CBF', -]; diff --git a/frontend/frontend/src/components/Wrapped/index.js b/frontend/frontend/src/components/Wrapped/index.js deleted file mode 100644 index 7ce0d018..00000000 --- a/frontend/frontend/src/components/Wrapped/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export * from './Organization'; -export * from './Templates'; -export * from './Specifics'; diff --git a/frontend/frontend/src/components/index.js b/frontend/frontend/src/components/index.js index 5eb6a0a8..24b86338 100644 --- a/frontend/frontend/src/components/index.js +++ b/frontend/frontend/src/components/index.js @@ -3,6 +3,5 @@ import Preview from './Preview'; export * from './Generic'; export * from './Card'; export * from './Home'; -export * from './Wrapped'; export { Preview }; diff --git a/frontend/frontend/src/constants.js b/frontend/frontend/src/constants.js index 6e532c1c..8abbdab0 100644 --- a/frontend/frontend/src/constants.js +++ b/frontend/frontend/src/constants.js @@ -12,20 +12,12 @@ export const HOST = PROD : 'localhost:3000'; export const REDIRECT_URI = PROD - ? MODE === 'trends' - ? `https://${HOST}/frontend/user` - : 'https://www.githubtrends.io/user/wrapped' - : MODE === 'trends' - ? `http://${HOST}/frontend/user` - : 'http://localhost:3000/user/wrapped'; + ? `https://${HOST}/frontend/user` + : `http://${HOST}/frontend/user`; export const GITHUB_PRIVATE_AUTH_URL = `https://github.com/login/oauth/authorize?scope=user,repo&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}/private`; export const GITHUB_PUBLIC_AUTH_URL = `https://github.com/login/oauth/authorize?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}/public`; -export const WRAPPED_URL = PROD - ? 'https://www.githubwrapped.io' - : 'http://localhost:3001'; - export const BACKEND_URL = PROD ? 'https://api.githubtrends.io' : 'http://localhost:8000'; diff --git a/frontend/frontend/src/index.js b/frontend/frontend/src/index.js index cc3c4b1a..69052507 100644 --- a/frontend/frontend/src/index.js +++ b/frontend/frontend/src/index.js @@ -4,7 +4,7 @@ import ReactDOM from 'react-dom/client'; import { Provider } from 'react-redux'; import configureStore from './redux/store'; -import { AppTrends, AppWrapped } from './pages/App'; +import { AppTrends } from './pages/App'; import './index.css'; import { MODE } from './constants'; @@ -19,15 +19,7 @@ if (MODE === 'trends') { , ); -} else if (MODE === 'wrapped') { - root.render( - - - , - ); } else { // Throw an error if the mode is not set correctly. - throw new Error( - 'REACT_APP_MODE must be set to "trends" or "wrapped" in your .env file.', - ); + throw new Error('REACT_APP_MODE must be set to "trends" in your .env file.'); } diff --git a/frontend/frontend/src/pages/App/AppTrends.js b/frontend/frontend/src/pages/App/AppTrends.js index 6dc10974..0e58f649 100644 --- a/frontend/frontend/src/pages/App/AppTrends.js +++ b/frontend/frontend/src/pages/App/AppTrends.js @@ -14,42 +14,13 @@ import { import Header from './Header'; import LandingScreen from '../Landing'; -import DemoScreen from '../Demo'; import { SignUpScreen } from '../Auth'; import HomeScreen from '../Home'; import SettingsScreen from '../Settings'; import { NoMatchScreen } from '../Misc'; import { getUserMetadata } from '../../api'; -import { WRAPPED_URL } from '../../constants'; import Footer from './Footer'; -function WrappedAuthRedirectScreen() { - // for wrapped auth redirects - const { rest } = useParams(); - useEffect(() => { - const code = new URLSearchParams(window.location.search).get('code'); - window.location.href = `${WRAPPED_URL}/${rest}?code=${code}`; - }, [rest]); - - return null; -} - -function WrappedRedirectScreen() { - // redirects /wrapped/* to https://www.githubwrapped.com/* - const { userId, year } = useParams(); - useEffect(() => { - if (userId) { - if (year) { - window.location.href = `${WRAPPED_URL}/${userId}/${year}`; - } else { - window.location.href = `${WRAPPED_URL}/${userId}`; - } - } else { - window.location.href = `${WRAPPED_URL}/`; - } - }, [userId, year]); -} - function App() { const userId = useSelector((state) => state.user.userId); const userKey = useSelector((state) => state.user.userKey); @@ -82,23 +53,8 @@ function App() { {!isAuthenticated && ( } /> )} - } /> - } - /> } /> - } - /> - } - /> - } /> } /> - } /> } /> } /> diff --git a/frontend/frontend/src/pages/App/AppWrapped.js b/frontend/frontend/src/pages/App/AppWrapped.js deleted file mode 100644 index 4972b180..00000000 --- a/frontend/frontend/src/pages/App/AppWrapped.js +++ /dev/null @@ -1,57 +0,0 @@ -import React, { useEffect } from 'react'; -import { useSelector, useDispatch } from 'react-redux'; - -import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; - -import Header from './Header'; -import { SignUpScreen } from '../Auth'; -import { SelectUserScreen, WrappedScreen } from '../Wrapped'; -import { NoMatchScreen } from '../Misc'; - -import { setUserAccess as _setPrivateAccess } from '../../redux/actions/userActions'; -import { getUserMetadata } from '../../api'; -import Footer from './Footer'; - -function App() { - const userId = useSelector((state) => state.user.userId); - const isAuthenticated = userId && userId.length > 0; - - const dispatch = useDispatch(); - const setPrivateAccess = (access) => dispatch(_setPrivateAccess(access)); - - useEffect(() => { - async function getPrivateAccess() { - if (userId && userId.length > 0) { - const result = await getUserMetadata(userId); - if (result !== null && result.private_access !== undefined) { - setPrivateAccess(result.private_access); - } - } - } - getPrivateAccess(); - }, [userId]); - - return ( -
- -
-
- - {!isAuthenticated && ( - } /> - )} - } /> - } /> - } /> - } /> - } /> - } /> - -
-
- -
- ); -} - -export default App; diff --git a/frontend/frontend/src/pages/App/Header.js b/frontend/frontend/src/pages/App/Header.js index c29e2930..fc7f8b89 100644 --- a/frontend/frontend/src/pages/App/Header.js +++ b/frontend/frontend/src/pages/App/Header.js @@ -10,7 +10,7 @@ import { MdSettings as SettingsIcon } from 'react-icons/md'; import { logout as _logout } from '../../redux/actions/userActions'; import appIcon from '../../assets/appLogo64.png'; import { classnames } from '../../utils'; -import { GITHUB_PUBLIC_AUTH_URL, WRAPPED_URL } from '../../constants'; +import { GITHUB_PUBLIC_AUTH_URL } from '../../constants'; const propTypes = { to: PropTypes.string.isRequired, @@ -79,26 +79,7 @@ const Header = ({ mode }) => { {mode === 'trends' && ( GitHub Trends )} - {mode === 'wrapped' && ( - GitHub Wrapped - )} - {/* Pages: Wrapped, Dashboard, Demo */} - {mode === 'trends' && ( -
- - Wrapped - - {isAuthenticated ? ( - Dashboard - ) : ( - Demo - )} -
- )} {/* Auth Pages: Sign Up, Log In, Log Out */}
{isAuthenticated ? ( @@ -144,18 +125,9 @@ const Header = ({ mode }) => {
{mode === 'trends' && ( <> - setToggle(false)}> - Wrapped + setToggle(false)}> + Dashboard - {isAuthenticated ? ( - setToggle(false)}> - Dashboard - - ) : ( - setToggle(false)}> - Demo - - )} )} {isAuthenticated ? ( diff --git a/frontend/frontend/src/pages/App/index.js b/frontend/frontend/src/pages/App/index.js index fb2616ef..d1a73173 100644 --- a/frontend/frontend/src/pages/App/index.js +++ b/frontend/frontend/src/pages/App/index.js @@ -1,4 +1,3 @@ import AppTrends from './AppTrends'; -import AppWrapped from './AppWrapped'; -export { AppTrends, AppWrapped }; +export { AppTrends }; diff --git a/frontend/frontend/src/pages/Demo/Demo.js b/frontend/frontend/src/pages/Demo/Demo.js deleted file mode 100644 index 573a33db..00000000 --- a/frontend/frontend/src/pages/Demo/Demo.js +++ /dev/null @@ -1,130 +0,0 @@ -import React, { useEffect, useState } from 'react'; - -import { Link } from 'react-router-dom'; - -import { Button, SvgInline } from '../../components'; -import { HOST } from '../../constants'; -import { classnames } from '../../utils'; - -const DemoScreen = () => { - const [userName, setUserName] = useState(''); - const [selectedUserName, setSelectedUserName] = useState(''); - const [loading, setLoading] = useState(false); - - let userNameInput; - - useEffect(() => { - userNameInput.focus(); - }, [userNameInput]); - - const [error, setError] = useState(''); - - const handleSubmit = async () => { - setLoading(true); - setSelectedUserName(userName); - setLoading(false); - }; - - const firstCardUrl = - selectedUserName.length > 0 - ? `https://${HOST}/api?username=${selectedUserName}&client=demo` - : `https://${HOST}/api?username=anuraghazra&client=demo`; - - const secondCardUrl = - selectedUserName.length > 0 - ? `https://${HOST}/api/top-langs?username=${selectedUserName}&client=demo` - : `https://${HOST}/api/top-langs?username=anuraghazra&client=demo`; - - return ( -
-
-
-

- GitHub Trends Demo -

-

- This is a demo of the GitHub Trends API. Enter your GitHub username - to see statistics about your top languages and repositories from the - past month. -

-
-

Enter your GitHub username to get started!

-
- { - userNameInput = input; - }} - placeholder="Enter Username" - className={classnames( - 'bg-white text-gray-700 w-full input input-bordered rounded-sm', - error && 'input-error', - )} - onChange={(e) => { - setUserName(e.target.value); - setError(''); - }} - onKeyPress={async (e) => { - if (e.key === 'Enter') { - handleSubmit(); - } - }} - /> - -
- {error ? ( -
- Error: {error} -
- ) : ( -
- )} -
-

- This demo uses a public access token that is heavily rate limited. - For full customization, private contributions, and a personal access - token, create an account instead! -

-
- -
-
-
-
-
-

- {selectedUserName === '' - ? 'Enter a Username' - : `Example Cards for ${selectedUserName}`} -

-
-
- -
-
- -
-
-
-
-
- ); -}; - -export default DemoScreen; diff --git a/frontend/frontend/src/pages/Demo/index.js b/frontend/frontend/src/pages/Demo/index.js deleted file mode 100644 index 4c933a56..00000000 --- a/frontend/frontend/src/pages/Demo/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import DemoScreen from './Demo'; - -export default DemoScreen; diff --git a/frontend/frontend/src/pages/Landing/Landing.js b/frontend/frontend/src/pages/Landing/Landing.js index f6604edc..2a97c72c 100644 --- a/frontend/frontend/src/pages/Landing/Landing.js +++ b/frontend/frontend/src/pages/Landing/Landing.js @@ -9,12 +9,10 @@ import { FaCheck as CheckIcon, FaGithub as GithubIcon } from 'react-icons/fa'; import { Button, Preview } from '../../components'; import mockup from '../../assets/mockup.png'; -import wrapped from '../../assets/wrapped1.png'; import avgupta456Langs from '../../assets/avgupta456_langs.png'; import tiangoloRepos from '../../assets/tiangolo_repos.png'; import reininkRepos from '../../assets/reinink_repos.png'; import dhermesLangs from '../../assets/dhermes_langs.png'; -import { WRAPPED_URL } from '../../constants'; function LandingScreen() { const userId = useSelector((state) => state.user.userId); @@ -93,9 +91,9 @@ function LandingScreen() {


- + {!isAuthenticated && ( @@ -108,57 +106,6 @@ function LandingScreen() {
-
-
-

- Reflect on your year -
- with GitHub Wrapped -
-

-

1. Detailed

-

- GitHub Wrapped provides a breakdown of your contributions by date, - by date, time, repository, and language. Over 20 stats are - displayed. -

-
-

2. Visual

-

- Understand your coding contributions like never before with an - interactive calendar, bar charts, pie charts, and more. -

-
-

3. Public

-

- Share your GitHub Wrapped link with your friends and colleagues and - take a look at their contributions too.{' '} - No account required, although rate limiting may - apply. -

-
-
- - - - - - -
-
-
-
- preview -
-
-

GitHub Trends

@@ -211,11 +158,6 @@ function LandingScreen() {

Ready to get started?

Create an account today.

- - - - -
-

- Step 2: Enter your GitHub username! -

-
- { - userNameInput = input; - }} - placeholder="Enter Username" - className={classnames( - 'bg-white text-gray-700 w-full input input-bordered rounded-sm', - error && 'input-error', - )} - defaultValue={userName} - onChange={(e) => { - setUserName(e.target.value); - setError(''); - }} - onKeyPress={async (e) => { - if (e.key === 'Enter') { - handleSubmit(); - } - }} - /> - -
- {error ? ( -
- Error: {error} -
- ) : ( -
- )} -
-

-
-
- -
-
-
- -
-
-

See some examples

-
- {[ - { - name: 'Linus Torvalds', - username: 'torvalds', - url: 'https://avatars.githubusercontent.com/u/1024025?v=4', - blurb: 'Creator of Linux', - }, - { - name: 'Evan You', - username: 'yyx990803', - url: 'https://avatars.githubusercontent.com/u/499550?v=4', - blurb: 'Creator of Vue', - }, - { - name: 'shadcn', - username: 'shadcn', - url: 'https://avatars.githubusercontent.com/u/124599?v=4', - blurb: 'Vercel, shadcn/ui', - }, - { - name: 'Sindre Sorhus', - username: 'sindresorhus', - url: 'https://avatars.githubusercontent.com/u/170270?v=4', - blurb: 'Open-sourcer', - }, - ].map((user) => ( -
- -
- {user.username} -
- - {user.name} - -

{user.blurb}

-
-
- -
- ))} -
-
-
-
-
-

GitHub Trends

-

- GitHub Trends dives deep into the GitHub API to bring you insightful - metrics and visualizations. We access individual commits to compute - accurate and granular statistics. -

-
- {[ - { - header: 'Measures Contribs', - text: 'Calculates your stats on a per-contribution level, allowing for deeper insights', - }, - { - header: 'LOC Insights', - text: 'See aggregate stats on lines of code (LOC) written across all contributions', - }, - { - header: 'Language Breakdowns', - text: 'Showcase your favorite languages with LOC language breakdowns', - }, - { - header: 'Private Mode', - text: 'Use a PAT to avoid rate limiting and include private contributions', - }, - { - header: 'Exciting Visualizations', - text: 'Visualize your contributions with bar graphs, pie charts, and more', - }, - { - header: 'Shareable Stats', - text: 'Easily add your cards to your GitHub and share them online', - }, - ].map((item, index) => ( - // eslint-disable-next-line react/no-array-index-key -
-
- -
-
-

{item.header}

-

{item.text}

-
-
- ))} -
-
-
- - ); -}; - -export default SelectUserScreen; diff --git a/frontend/frontend/src/pages/Wrapped/Wrapped.js b/frontend/frontend/src/pages/Wrapped/Wrapped.js deleted file mode 100644 index 3017e240..00000000 --- a/frontend/frontend/src/pages/Wrapped/Wrapped.js +++ /dev/null @@ -1,323 +0,0 @@ -/* eslint-disable react/jsx-one-expression-per-line */ - -import React, { useEffect, useState } from 'react'; -import { useSelector } from 'react-redux'; - -import { useParams, Link } from 'react-router-dom'; -import { toPng } from 'html-to-image'; -import download from 'downloadjs'; -import { FaArrowLeft as LeftArrowIcon } from 'react-icons/fa'; -import { BsImage as ImageIcon, BsInfoCircle } from 'react-icons/bs'; -import Select from 'react-select'; -import { ClipLoader } from 'react-spinners'; - -import { getWrapped } from '../../api'; -import { - WrappedSection, - Numeric, - NumericOutOf, - Calendar, - hoverScale, - singleHoverScale, - BarMonth, - BarDay, - PieLangs, - PieRepos, - SwarmDay, - NumericPlusLOC, - NumericMinusLOC, - NumericBothLOC, - NumericBestDay, -} from '../../components'; -import Radar from '../../components/Wrapped/Specifics/Radar'; -import { LoadingScreen } from './sections'; -import { classnames } from '../../utils'; -import { CURR_YEAR } from '../../constants'; - -const WrappedScreen = () => { - // eslint-disable-next-line prefer-const - let { userId, year } = useParams(); - year = year || `${CURR_YEAR}`; - - const currUserId = useSelector((state) => state.user.userId); - const usePrivate = useSelector((state) => state.user.privateAccess); - - const [data, setData] = useState({}); - const [isLoading, setIsLoading] = useState(true); - const [highlightDays, setHighlightDays] = useState([]); - const [highlightColors, setHighlightColors] = useState(hoverScale); - - const [downloadLoading, setDownloadLoading] = useState(false); - - // eslint-disable-next-line no-unused-vars - const downloadImage = async () => { - const dataUrl = await toPng(document.getElementById('screenshot-div')); - download(dataUrl, 'github-wrapped.png'); - }; - - useEffect(() => { - async function getData() { - if (userId?.length > 0 && year > 2010 && year <= CURR_YEAR) { - const output = await getWrapped(userId, year); - if ( - output !== null && - output !== undefined && - Object.keys(output).length > 0 - ) { - setData(output); - setIsLoading(false); - } - } - } - getData(); - }, [userId, year]); - - if (isLoading) { - return ; - } - - const startStreak = data?.numeric_data?.misc?.longest_streak_days?.[0] || 0; - const endStreak = data?.numeric_data?.misc?.longest_streak_days?.[1] || 0; - const startGap = data?.numeric_data?.misc?.longest_gap_days?.[0] || 0; - const endGap = data?.numeric_data?.misc?.longest_gap_days?.[1] || 0; - - const bestDayMonth = - data?.numeric_data?.misc?.best_day_date?.split('-')?.[1] || '-'; - const bestDayDay = - data?.numeric_data?.misc?.best_day_date?.split('-')?.[2] || '-'; - const bestDayYear = - data?.numeric_data?.misc?.best_day_date?.split('-')?.[0] || '-'; - - return ( -
-
- -
- {!downloadLoading && ( - - - - )} -

- {`${userId}'s`} -

-
-