diff --git a/app/package.json b/app/package.json index 60416d2a..f9be829d 100644 --- a/app/package.json +++ b/app/package.json @@ -26,6 +26,7 @@ "@types/react-slick": "^0.23.10", "@vitejs/plugin-basic-ssl": "^1.0.1", "apexcharts": "^3.41.0", + "date-fns": "^2.30.0", "dayjs": "^1.11.8", "detect-browser": "^5.3.0", "emotion-rgba": "^0.0.11", diff --git a/app/pnpm-lock.yaml b/app/pnpm-lock.yaml index ca81792f..2e61b69c 100644 --- a/app/pnpm-lock.yaml +++ b/app/pnpm-lock.yaml @@ -29,6 +29,9 @@ dependencies: apexcharts: specifier: ^3.41.0 version: 3.41.0 + date-fns: + specifier: ^2.30.0 + version: 2.30.0 dayjs: specifier: ^1.11.8 version: 1.11.8 @@ -6730,6 +6733,13 @@ packages: resolution: {integrity: sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g==} dev: true + /date-fns@2.30.0: + resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} + engines: {node: '>=0.11'} + dependencies: + '@babel/runtime': 7.22.5 + dev: false + /dayjs@1.11.8: resolution: {integrity: sha512-LcgxzFoWMEPO7ggRv1Y2N31hUf2R0Vj7fuy/m+Bg1K8rr+KAs1AEy4y9jd5DXe8pbHgX+srkHNS7TH6Q6ZhYeQ==} dev: false diff --git a/app/src/@shared/__generated__/gql.ts b/app/src/@shared/__generated__/gql.ts index ff1af3cf..2bd94feb 100644 --- a/app/src/@shared/__generated__/gql.ts +++ b/app/src/@shared/__generated__/gql.ts @@ -30,7 +30,7 @@ const documents = { "\n mutation ftLogin($ftCode: String!) {\n ftLogin(ftCode: $ftCode) {\n message\n accessToken\n refreshToken\n userId\n }\n }\n": types.FtLoginDocument, "\n query GetIndividualizedMessage {\n getMyInfo {\n lastValidatedTeam {\n status\n lastEventTime\n projectPreview {\n id\n name\n url\n }\n }\n isNewMember\n blackholedAt\n experienceRank\n scoreRank\n evalCountRank\n }\n }\n": types.GetIndividualizedMessageDocument, "\n query GetTigCountPerCoalitionByDateTemplate($dateTemplate: DateTemplate!) {\n getHomeCoalition {\n tigCountPerCoalitionByDateTemplate(dateTemplate: $dateTemplate) {\n data {\n coalition {\n ...coalitionFields\n }\n value\n }\n start\n end\n }\n }\n }\n": types.GetTigCountPerCoalitionByDateTemplateDocument, - "\n query GetScoreRecordsPerCoalition {\n getHomeCoalition {\n scoreRecordsPerCoalition {\n coalition {\n ...coalitionFields\n }\n records {\n at\n value\n }\n }\n }\n }\n": types.GetScoreRecordsPerCoalitionDocument, + "\n query GetScoreRecordsPerCoalition($last: Int!) {\n getHomeCoalition {\n scoreRecordsPerCoalition(last: $last) {\n coalition {\n ...coalitionFields\n }\n records {\n at\n value\n }\n }\n }\n }\n": types.GetScoreRecordsPerCoalitionDocument, "\n query GetTotalScoresPerCoalition {\n getHomeCoalition {\n totalScoresPerCoalition {\n coalition {\n ...coalitionFields\n }\n value\n }\n }\n }\n": types.GetTotalScoresPerCoalitionDocument, "\n query GetWinCountPerCoalition {\n getHomeCoalition {\n winCountPerCoalition {\n coalition {\n ...coalitionFields\n }\n value\n }\n }\n }\n": types.GetWinCountPerCoalitionDocument, "\n query GetAverageCommentLength {\n getHomeEval {\n averageCommentLength\n }\n }\n": types.GetAverageCommentLengthDocument, @@ -40,7 +40,7 @@ const documents = { "\n query GetCurrRegisteredCountRanking($limit: Int!) {\n getHomeTeam {\n currRegisteredCountRanking(limit: $limit) {\n projectPreview {\n ...projectPreviewFields\n }\n rank\n value\n }\n }\n }\n": types.GetCurrRegisteredCountRankingDocument, "\n query GetRecentExamResult {\n getHomeTeam {\n recentExamResult {\n data {\n resultPerRank {\n rank\n rate {\n total\n fields {\n key\n value\n }\n }\n }\n beginAt\n location\n }\n }\n }\n }\n": types.GetRecentExamResultDocument, "\n query GetTeamCloseRecords($last: Int!) {\n getHomeTeam {\n teamCloseRecords(last: $last) {\n at\n value\n }\n }\n }\n": types.GetTeamCloseRecordsDocument, - "\n query GetAliveUserCountRecords {\n getHomeUser {\n aliveUserCountRecords {\n at\n value\n }\n }\n }\n": types.GetAliveUserCountRecordsDocument, + "\n query GetDailyAliveUserCountRecords($last: Int!) {\n getHomeUser {\n dailyAliveUserCountRecords(last: $last) {\n at\n value\n }\n }\n }\n": types.GetDailyAliveUserCountRecordsDocument, "\n query GetAverageDurationPerCircle {\n getHomeUser {\n averageDurationPerCircle {\n circle\n value\n }\n }\n }\n": types.GetAverageDurationPerCircleDocument, "\n query GetBlackholedCountPerCircle {\n getHomeUser {\n blackholedCountPerCircle {\n circle\n value\n }\n }\n }\n": types.GetBlackholedCountPerCircleDocument, "\n query GetBlackholedCountRecords($last: Int!) {\n getHomeUser {\n blackholedCountRecords(last: $last) {\n at\n value\n }\n }\n }\n": types.GetBlackholedCountRecordsDocument, @@ -181,7 +181,7 @@ export function gql(source: "\n query GetTigCountPerCoalitionByDateTemplate($da /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function gql(source: "\n query GetScoreRecordsPerCoalition {\n getHomeCoalition {\n scoreRecordsPerCoalition {\n coalition {\n ...coalitionFields\n }\n records {\n at\n value\n }\n }\n }\n }\n"): (typeof documents)["\n query GetScoreRecordsPerCoalition {\n getHomeCoalition {\n scoreRecordsPerCoalition {\n coalition {\n ...coalitionFields\n }\n records {\n at\n value\n }\n }\n }\n }\n"]; +export function gql(source: "\n query GetScoreRecordsPerCoalition($last: Int!) {\n getHomeCoalition {\n scoreRecordsPerCoalition(last: $last) {\n coalition {\n ...coalitionFields\n }\n records {\n at\n value\n }\n }\n }\n }\n"): (typeof documents)["\n query GetScoreRecordsPerCoalition($last: Int!) {\n getHomeCoalition {\n scoreRecordsPerCoalition(last: $last) {\n coalition {\n ...coalitionFields\n }\n records {\n at\n value\n }\n }\n }\n }\n"]; /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -221,7 +221,7 @@ export function gql(source: "\n query GetTeamCloseRecords($last: Int!) {\n g /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function gql(source: "\n query GetAliveUserCountRecords {\n getHomeUser {\n aliveUserCountRecords {\n at\n value\n }\n }\n }\n"): (typeof documents)["\n query GetAliveUserCountRecords {\n getHomeUser {\n aliveUserCountRecords {\n at\n value\n }\n }\n }\n"]; +export function gql(source: "\n query GetDailyAliveUserCountRecords($last: Int!) {\n getHomeUser {\n dailyAliveUserCountRecords(last: $last) {\n at\n value\n }\n }\n }\n"): (typeof documents)["\n query GetDailyAliveUserCountRecords($last: Int!) {\n getHomeUser {\n dailyAliveUserCountRecords(last: $last) {\n at\n value\n }\n }\n }\n"]; /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/app/src/@shared/__generated__/graphql.ts b/app/src/@shared/__generated__/graphql.ts index 62d9e762..b601c2ca 100644 --- a/app/src/@shared/__generated__/graphql.ts +++ b/app/src/@shared/__generated__/graphql.ts @@ -1022,7 +1022,9 @@ export type GetTigCountPerCoalitionByDateTemplateQueryVariables = Exact<{ export type GetTigCountPerCoalitionByDateTemplateQuery = { __typename?: 'Query', getHomeCoalition: { __typename?: 'HomeCoalition', tigCountPerCoalitionByDateTemplate: { __typename?: 'IntPerCoalitionDateRanged', start: string, end: string, data: Array<{ __typename?: 'IntPerCoalition', value: number, coalition: { __typename?: 'Coalition', id: number, name: string, imgUrl: string, coverUrl: string, color: string } }> } } }; -export type GetScoreRecordsPerCoalitionQueryVariables = Exact<{ [key: string]: never; }>; +export type GetScoreRecordsPerCoalitionQueryVariables = Exact<{ + last: Scalars['Int']; +}>; export type GetScoreRecordsPerCoalitionQuery = { __typename?: 'Query', getHomeCoalition: { __typename?: 'HomeCoalition', scoreRecordsPerCoalition: Array<{ __typename?: 'ScoreRecordPerCoalition', coalition: { __typename?: 'Coalition', id: number, name: string, imgUrl: string, coverUrl: string, color: string }, records: Array<{ __typename?: 'IntRecord', at: string, value: number }> }> } }; @@ -1078,10 +1080,12 @@ export type GetTeamCloseRecordsQueryVariables = Exact<{ export type GetTeamCloseRecordsQuery = { __typename?: 'Query', getHomeTeam: { __typename?: 'HomeTeam', teamCloseRecords: Array<{ __typename?: 'IntRecord', at: string, value: number }> } }; -export type GetAliveUserCountRecordsQueryVariables = Exact<{ [key: string]: never; }>; +export type GetDailyAliveUserCountRecordsQueryVariables = Exact<{ + last: Scalars['Int']; +}>; -export type GetAliveUserCountRecordsQuery = { __typename?: 'Query', getHomeUser: { __typename?: 'HomeUser', aliveUserCountRecords: Array<{ __typename?: 'IntRecord', at: string, value: number }> } }; +export type GetDailyAliveUserCountRecordsQuery = { __typename?: 'Query', getHomeUser: { __typename?: 'HomeUser', dailyAliveUserCountRecords: Array<{ __typename?: 'IntRecord', at: string, value: number }> } }; export type GetAverageDurationPerCircleQueryVariables = Exact<{ [key: string]: never; }>; @@ -1298,7 +1302,6 @@ export type GetDailyActivityDetailRecordsQueryVariables = Exact<{ args: Array | DailyActivityDetailRecordIdWithType; }>; - export type GetDailyActivityDetailRecordsQuery = { __typename?: 'Query', getPersonalGeneral: { __typename?: 'PersonalGeneral', dailyActivityDetailRecords: Array<{ __typename?: 'DailyEvaluationDetailRecord', type: DailyActivityType, teamId: number, correctorLogin: string, leaderLogin: string, projectName: string, beginAt: string, filledAt: string } | { __typename?: 'DailyEventDetailRecord', name: string, location: string, beginAt: string, endAt: string }> } }; export type GetLevelRecordsByLoginQueryVariables = Exact<{ @@ -1486,7 +1489,7 @@ export const GetEvalLogsDocument = {"kind":"Document","definitions":[{"kind":"Op export const FtLoginDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ftLogin"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"ftCode"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ftLogin"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"ftCode"},"value":{"kind":"Variable","name":{"kind":"Name","value":"ftCode"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"accessToken"}},{"kind":"Field","name":{"kind":"Name","value":"refreshToken"}},{"kind":"Field","name":{"kind":"Name","value":"userId"}}]}}]}}]} as unknown as DocumentNode; export const GetIndividualizedMessageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetIndividualizedMessage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getMyInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"lastValidatedTeam"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"lastEventTime"}},{"kind":"Field","name":{"kind":"Name","value":"projectPreview"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"isNewMember"}},{"kind":"Field","name":{"kind":"Name","value":"blackholedAt"}},{"kind":"Field","name":{"kind":"Name","value":"experienceRank"}},{"kind":"Field","name":{"kind":"Name","value":"scoreRank"}},{"kind":"Field","name":{"kind":"Name","value":"evalCountRank"}}]}}]}}]} as unknown as DocumentNode; export const GetTigCountPerCoalitionByDateTemplateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetTigCountPerCoalitionByDateTemplate"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateTemplate"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTemplate"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getHomeCoalition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tigCountPerCoalitionByDateTemplate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"dateTemplate"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateTemplate"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"coalition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"coalitionFields"}}]}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}},{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"coalitionFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Coalition"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"imgUrl"}},{"kind":"Field","name":{"kind":"Name","value":"coverUrl"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]} as unknown as DocumentNode; -export const GetScoreRecordsPerCoalitionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetScoreRecordsPerCoalition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getHomeCoalition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"scoreRecordsPerCoalition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"coalition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"coalitionFields"}}]}},{"kind":"Field","name":{"kind":"Name","value":"records"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"at"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"coalitionFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Coalition"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"imgUrl"}},{"kind":"Field","name":{"kind":"Name","value":"coverUrl"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]} as unknown as DocumentNode; +export const GetScoreRecordsPerCoalitionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetScoreRecordsPerCoalition"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"last"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getHomeCoalition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"scoreRecordsPerCoalition"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"last"},"value":{"kind":"Variable","name":{"kind":"Name","value":"last"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"coalition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"coalitionFields"}}]}},{"kind":"Field","name":{"kind":"Name","value":"records"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"at"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"coalitionFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Coalition"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"imgUrl"}},{"kind":"Field","name":{"kind":"Name","value":"coverUrl"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]} as unknown as DocumentNode; export const GetTotalScoresPerCoalitionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetTotalScoresPerCoalition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getHomeCoalition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalScoresPerCoalition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"coalition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"coalitionFields"}}]}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"coalitionFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Coalition"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"imgUrl"}},{"kind":"Field","name":{"kind":"Name","value":"coverUrl"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]} as unknown as DocumentNode; export const GetWinCountPerCoalitionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetWinCountPerCoalition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getHomeCoalition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"winCountPerCoalition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"coalition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"coalitionFields"}}]}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"coalitionFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Coalition"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"imgUrl"}},{"kind":"Field","name":{"kind":"Name","value":"coverUrl"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]} as unknown as DocumentNode; export const GetAverageCommentLengthDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAverageCommentLength"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getHomeEval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"averageCommentLength"}}]}}]}}]} as unknown as DocumentNode; @@ -1496,7 +1499,7 @@ export const GetTotalEvalCountDocument = {"kind":"Document","definitions":[{"kin export const GetCurrRegisteredCountRankingDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetCurrRegisteredCountRanking"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getHomeTeam"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currRegisteredCountRanking"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"projectPreview"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"projectPreviewFields"}}]}},{"kind":"Field","name":{"kind":"Name","value":"rank"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"projectPreviewFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ProjectPreview"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"circle"}}]}}]} as unknown as DocumentNode; export const GetRecentExamResultDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetRecentExamResult"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getHomeTeam"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"recentExamResult"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"resultPerRank"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"rank"}},{"kind":"Field","name":{"kind":"Name","value":"rate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"fields"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"beginAt"}},{"kind":"Field","name":{"kind":"Name","value":"location"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const GetTeamCloseRecordsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetTeamCloseRecords"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"last"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getHomeTeam"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"teamCloseRecords"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"last"},"value":{"kind":"Variable","name":{"kind":"Name","value":"last"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"at"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]}}]} as unknown as DocumentNode; -export const GetAliveUserCountRecordsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAliveUserCountRecords"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getHomeUser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"aliveUserCountRecords"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"at"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]}}]} as unknown as DocumentNode; +export const GetDailyAliveUserCountRecordsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetDailyAliveUserCountRecords"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"last"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getHomeUser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dailyAliveUserCountRecords"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"last"},"value":{"kind":"Variable","name":{"kind":"Name","value":"last"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"at"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]}}]} as unknown as DocumentNode; export const GetAverageDurationPerCircleDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAverageDurationPerCircle"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getHomeUser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"averageDurationPerCircle"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"circle"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]}}]} as unknown as DocumentNode; export const GetBlackholedCountPerCircleDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetBlackholedCountPerCircle"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getHomeUser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"blackholedCountPerCircle"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"circle"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]}}]} as unknown as DocumentNode; export const GetBlackholedCountRecordsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetBlackholedCountRecords"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"last"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getHomeUser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"blackholedCountRecords"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"last"},"value":{"kind":"Variable","name":{"kind":"Name","value":"last"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"at"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]}}]} as unknown as DocumentNode; diff --git a/app/src/@shared/components/Chart/hooks/useDefaultOptions.ts b/app/src/@shared/components/Chart/hooks/useDefaultOptions.ts index ea2f098d..d44ecce4 100644 --- a/app/src/@shared/components/Chart/hooks/useDefaultOptions.ts +++ b/app/src/@shared/components/Chart/hooks/useDefaultOptions.ts @@ -25,10 +25,16 @@ export const useDefaultOptions = () => { const defaultOptions: ApexCharts.ApexOptions = { chart: { toolbar: { - show: false, - }, - zoom: { - enabled: false, + show: true, + tools: { + download: false, + selection: false, + zoom: true, + zoomin: true, + zoomout: true, + pan: false, + reset: true, + }, }, fontFamily: "'Pretendard Variable', Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, 'Helvetica Neue', 'Segoe UI', 'Apple SD Gothic Neo', 'Noto Sans KR', 'Malgun Gothic', 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', sans-serif", diff --git a/app/src/@shared/constants/date.ts b/app/src/@shared/constants/date.ts index 037297eb..4399025b 100644 --- a/app/src/@shared/constants/date.ts +++ b/app/src/@shared/constants/date.ts @@ -1,3 +1,5 @@ +import { differenceInCalendarDays, differenceInCalendarMonths } from 'date-fns'; + export const MILLISECONDS = { SECOND: 1000, MINUTE: 1000 * 60, @@ -8,6 +10,16 @@ export const MILLISECONDS = { YEAR: 1000 * 3600 * 24 * 365, } as const; +export const FT_BEGIN_AT = new Date('2020-01-20'); +export const CALENDAR_MONTHS_FROM_FT_BEGIN_AT = differenceInCalendarMonths( + new Date(), + FT_BEGIN_AT, +); +export const CALENDAR_DAYS_FROM_FT_BEGIN_AT = differenceInCalendarDays( + new Date(), + FT_BEGIN_AT, +); + export const MINUTES = { MILLISECOND: 1 / 1000, SECOND: 1 / 60, diff --git a/app/src/@shared/utils/injectEmptyDay.ts b/app/src/@shared/utils/injectEmptyDay.ts new file mode 100644 index 00000000..f315a570 --- /dev/null +++ b/app/src/@shared/utils/injectEmptyDay.ts @@ -0,0 +1,29 @@ +import { isSameDay, isSameMonth, isSameYear } from 'date-fns'; + +export const injectEmptyDay = ( + series: { x: Date; y: number }[], + last: number, +) => { + const result = []; + + let currIndex = 0; + + for (let i = last - 1; i >= 0; i--) { + const date = new Date(); + date.setDate(date.getDate() - i); + + if ( + currIndex < series.length && + isSameYear(series[currIndex].x, date) && + isSameMonth(series[currIndex].x, date) && + isSameDay(series[currIndex].x, date) + ) { + result.push(series[currIndex]); + currIndex++; + } else { + result.push({ x: date, y: 0 }); + } + } + + return result; +}; diff --git a/app/src/@shared/utils/injectEmptyMonth.ts b/app/src/@shared/utils/injectEmptyMonth.ts new file mode 100644 index 00000000..49b7e143 --- /dev/null +++ b/app/src/@shared/utils/injectEmptyMonth.ts @@ -0,0 +1,28 @@ +import { isSameMonth, isSameYear } from 'date-fns'; + +export const injectEmptyMonth = ( + series: { x: Date; y: number }[], + last: number, +) => { + const result = []; + + let currIndex = 0; + + for (let i = last - 1; i >= 0; i--) { + const date = new Date(); + date.setMonth(date.getMonth() - i); + + if ( + currIndex < series.length && + isSameYear(series[currIndex].x, date) && + isSameMonth(series[currIndex].x, date) + ) { + result.push(series[currIndex]); + currIndex++; + } else { + result.push({ x: date, y: 0 }); + } + } + + return result; +}; diff --git a/app/src/Calculator/dashboard-contents/LevelRecords.tsx b/app/src/Calculator/dashboard-contents/LevelRecords.tsx index 670727f6..cfa4977b 100644 --- a/app/src/Calculator/dashboard-contents/LevelRecords.tsx +++ b/app/src/Calculator/dashboard-contents/LevelRecords.tsx @@ -68,6 +68,14 @@ const LevelCalculatorChart = ({ series }: LevelCalculatorChartProps) => { const subjectLength = series[0].data.length; const options: ApexCharts.ApexOptions = { + chart: { + toolbar: { + show: false, + tools: { + zoom: false, + }, + }, + }, xaxis: { overwriteCategories: series[0].data.map((item) => { if (subjectLength > MAX_XAXIS_COUNT) { diff --git a/app/src/Home/dashboard-contents/Coalition/ScoreRecordsPerCoalition.tsx b/app/src/Home/dashboard-contents/Coalition/ScoreRecordsPerCoalition.tsx index 0971260f..fc0a0b69 100644 --- a/app/src/Home/dashboard-contents/Coalition/ScoreRecordsPerCoalition.tsx +++ b/app/src/Home/dashboard-contents/Coalition/ScoreRecordsPerCoalition.tsx @@ -8,13 +8,15 @@ import { DashboardContentLoading, DashboardContentNotFound, } from '@shared/components/DashboardContentView/Error'; +import { CALENDAR_MONTHS_FROM_FT_BEGIN_AT } from '@shared/constants/date'; import { kiloFormatter } from '@shared/utils/formatters/kiloFormatter'; import { numberWithUnitFormatter } from '@shared/utils/formatters/numberWithUnitFormatter'; +import { injectEmptyMonth } from '@shared/utils/injectEmptyMonth'; const GET_SCORE_RECORDS_PER_COALITION = gql(/* GraphQL */ ` - query GetScoreRecordsPerCoalition { + query GetScoreRecordsPerCoalition($last: Int!) { getHomeCoalition { - scoreRecordsPerCoalition { + scoreRecordsPerCoalition(last: $last) { coalition { ...coalitionFields } @@ -29,7 +31,13 @@ const GET_SCORE_RECORDS_PER_COALITION = gql(/* GraphQL */ ` export const ScoreRecordsPerCoalition = () => { const title = '코알리숑 스코어 변동 추이'; - const { loading, error, data } = useQuery(GET_SCORE_RECORDS_PER_COALITION); + const last = CALENDAR_MONTHS_FROM_FT_BEGIN_AT + 1; + + const { loading, error, data } = useQuery(GET_SCORE_RECORDS_PER_COALITION, { + variables: { + last, + }, + }); if (loading) { return ; @@ -45,10 +53,13 @@ export const ScoreRecordsPerCoalition = () => { const colors: string[] = []; const series = scoreRecordsPerCoalition.map(({ coalition, records }) => { - const seriesData = records.map(({ at, value }) => ({ - x: at, - y: value, - })); + const seriesData = injectEmptyMonth( + records.map(({ at, value }) => ({ + x: new Date(at), + y: value, + })), + last, + ); colors.push(coalition.color ?? 'black'); return { name: coalition.name, diff --git a/app/src/Home/dashboard-contents/Eval/EvalCountRecords.tsx b/app/src/Home/dashboard-contents/Eval/EvalCountRecords.tsx index 8edaec09..84efbd03 100644 --- a/app/src/Home/dashboard-contents/Eval/EvalCountRecords.tsx +++ b/app/src/Home/dashboard-contents/Eval/EvalCountRecords.tsx @@ -9,6 +9,7 @@ import { DashboardContentNotFound, } from '@shared/components/DashboardContentView/Error'; import { numberWithUnitFormatter } from '@shared/utils/formatters/numberWithUnitFormatter'; +import { injectEmptyDay } from '@shared/utils/injectEmptyDay'; const GET_EVAL_COUNT_RECORDS = gql(/* GraphQL */ ` query GetEvalCountRecords($last: Int!) { @@ -23,9 +24,11 @@ const GET_EVAL_COUNT_RECORDS = gql(/* GraphQL */ ` export const EvalCountRecords = () => { const title = '일간 평가 횟수 추이'; + const last = 180; + const { loading, error, data } = useQuery(GET_EVAL_COUNT_RECORDS, { variables: { - last: 30, + last, }, }); if (loading) { @@ -39,10 +42,13 @@ export const EvalCountRecords = () => { } const { evalCountRecords } = data.getHomeEval; - const seriesData = evalCountRecords.map(({ at, value }) => ({ - x: at, - y: value, - })); + const seriesData = injectEmptyDay( + evalCountRecords.map(({ at, value }) => ({ + x: new Date(at), + y: value, + })), + last, + ); const series: ApexAxisChartSeries = [ { name: '평가 횟수', @@ -72,7 +78,7 @@ const EvalCountRecordsChart = ({ series }: EvalCountRecordsChartProps) => { }, tooltip: { x: { - format: 'M월 d일', + format: 'yyyy년 M월 d일', }, y: { formatter: (value) => numberWithUnitFormatter(value, '회'), diff --git a/app/src/Home/dashboard-contents/Team/TeamCloseRecords.tsx b/app/src/Home/dashboard-contents/Team/TeamCloseRecords.tsx index 4e36bf06..ebb0901a 100644 --- a/app/src/Home/dashboard-contents/Team/TeamCloseRecords.tsx +++ b/app/src/Home/dashboard-contents/Team/TeamCloseRecords.tsx @@ -9,6 +9,7 @@ import { DashboardContentNotFound, } from '@shared/components/DashboardContentView/Error'; import { numberWithUnitFormatter } from '@shared/utils/formatters/numberWithUnitFormatter'; +import { injectEmptyDay } from '@shared/utils/injectEmptyDay'; const GET_TEAM_CLOSE_RECORDS = gql(/* GraphQL */ ` query GetTeamCloseRecords($last: Int!) { @@ -23,9 +24,11 @@ const GET_TEAM_CLOSE_RECORDS = gql(/* GraphQL */ ` export const TeamCloseRecords = () => { const title = '일간 팀 제출 횟수 추이'; + const last = 180; + const { loading, error, data } = useQuery(GET_TEAM_CLOSE_RECORDS, { variables: { - last: 30, + last, }, }); if (loading) { @@ -39,10 +42,13 @@ export const TeamCloseRecords = () => { } const { teamCloseRecords } = data.getHomeTeam; - const seriesData = teamCloseRecords.map(({ at, value }) => ({ - x: at, - y: value, - })); + const seriesData = injectEmptyDay( + teamCloseRecords.map(({ at, value }) => ({ + x: new Date(at), + y: value, + })), + last, + ); const series: ApexAxisChartSeries = [ { name: '제출 횟수', @@ -72,7 +78,7 @@ const EvalCountRecordsChart = ({ series }: EvalCountRecordsChartProps) => { }, tooltip: { x: { - format: 'M월 d일', + format: 'yyyy년 M월 d일', }, y: { formatter: (value) => numberWithUnitFormatter(value, '회'), diff --git a/app/src/Home/dashboard-contents/User/AliveUserCountRecords.tsx b/app/src/Home/dashboard-contents/User/AliveUserCountRecords.tsx index 133f5a01..7ba1780d 100644 --- a/app/src/Home/dashboard-contents/User/AliveUserCountRecords.tsx +++ b/app/src/Home/dashboard-contents/User/AliveUserCountRecords.tsx @@ -11,10 +11,10 @@ import { import { InfoTooltip } from '@shared/components/InfoTooltip'; import { numberWithUnitFormatter } from '@shared/utils/formatters/numberWithUnitFormatter'; -const GET_ALIVE_USER_COUNT_RECORDS = gql(/* GraphQL */ ` - query GetAliveUserCountRecords { +const GET_DAILY_ALIVE_USER_COUNT_RECORDS = gql(/* GraphQL */ ` + query GetDailyAliveUserCountRecords($last: Int!) { getHomeUser { - aliveUserCountRecords { + dailyAliveUserCountRecords(last: $last) { at value } @@ -24,7 +24,16 @@ const GET_ALIVE_USER_COUNT_RECORDS = gql(/* GraphQL */ ` export const AliveUserCountRecords = () => { const title = '여행 중인 유저 수 추이'; - const { loading, error, data } = useQuery(GET_ALIVE_USER_COUNT_RECORDS); + const last = 365; + + const { loading, error, data } = useQuery( + GET_DAILY_ALIVE_USER_COUNT_RECORDS, + { + variables: { + last, + }, + }, + ); if (loading) { return ; @@ -36,9 +45,9 @@ export const AliveUserCountRecords = () => { return ; } - const { aliveUserCountRecords } = data.getHomeUser; - const seriesData = aliveUserCountRecords.map(({ at, value }) => ({ - x: at, + const { dailyAliveUserCountRecords } = data.getHomeUser; + const seriesData = dailyAliveUserCountRecords.map(({ at, value }) => ({ + x: new Date(at), y: value, })); const series: ApexAxisChartSeries = [ @@ -83,7 +92,7 @@ const ActiveUserCountRecordsChart = ({ }, tooltip: { x: { - format: 'yyyy년 M월', + format: 'yyyy년 M월 d일', }, y: { formatter: (value) => numberWithUnitFormatter(value, '명'), diff --git a/app/src/Home/dashboard-contents/User/BlackholedCountRecords.tsx b/app/src/Home/dashboard-contents/User/BlackholedCountRecords.tsx index 5897d531..bbb7bd1c 100644 --- a/app/src/Home/dashboard-contents/User/BlackholedCountRecords.tsx +++ b/app/src/Home/dashboard-contents/User/BlackholedCountRecords.tsx @@ -8,7 +8,9 @@ import { DashboardContentLoading, DashboardContentNotFound, } from '@shared/components/DashboardContentView/Error'; +import { CALENDAR_MONTHS_FROM_FT_BEGIN_AT } from '@shared/constants/date'; import { numberWithUnitFormatter } from '@shared/utils/formatters/numberWithUnitFormatter'; +import { injectEmptyMonth } from '@shared/utils/injectEmptyMonth'; const GET_BLACKHOLED_COUNT_RECORDS = gql(/* GraphQL */ ` query GetBlackholedCountRecords($last: Int!) { @@ -23,9 +25,11 @@ const GET_BLACKHOLED_COUNT_RECORDS = gql(/* GraphQL */ ` export const BlackholedCountRecords = () => { const title = '월간 블랙홀 인원 추이'; + const last = CALENDAR_MONTHS_FROM_FT_BEGIN_AT + 1; + const { loading, error, data } = useQuery(GET_BLACKHOLED_COUNT_RECORDS, { variables: { - last: 12, + last, }, }); @@ -40,10 +44,14 @@ export const BlackholedCountRecords = () => { } const { blackholedCountRecords } = data.getHomeUser; - const seriesData = blackholedCountRecords.map(({ at, value }) => ({ - x: at, - y: value, - })); + const seriesData = injectEmptyMonth( + blackholedCountRecords.map(({ at, value }) => ({ + x: new Date(at), + y: value, + })), + last, + ); + const series: ApexAxisChartSeries = [ { name: '인원수', diff --git a/app/src/Landing/components/Introduction.tsx b/app/src/Landing/components/Introduction.tsx index 61ef70f0..e7de8aed 100644 --- a/app/src/Landing/components/Introduction.tsx +++ b/app/src/Landing/components/Introduction.tsx @@ -7,6 +7,7 @@ import 'slick-carousel/slick/slick.css'; import { CountUp } from 'use-count-up'; import { gql } from '@shared/__generated__'; +import { CALENDAR_DAYS_FROM_FT_BEGIN_AT } from '@shared/constants/date'; import { BoldText } from '@shared/ui-kit'; import { mq } from '@shared/utils/facepaint/mq'; import { useDeviceType } from '@shared/utils/react-responsive/useDeviceType'; @@ -47,7 +48,7 @@ export const Introduction = () => { const { data } = useQuery(GET_LANDING); const [introData, setIntroData] = useState({ - daysAfterBeginAt: 1262, + daysAfterBeginAt: CALENDAR_DAYS_FROM_FT_BEGIN_AT, aliveCount: 1030, blackholedCount: 1326, memberCount: 244, @@ -87,7 +88,6 @@ export const Introduction = () => { return; } const { - daysAfterBeginAt, aliveCount, blackholedCount, memberCount, @@ -98,7 +98,7 @@ export const Introduction = () => { }, } = data.getLanding; setIntroData({ - daysAfterBeginAt, + daysAfterBeginAt: CALENDAR_DAYS_FROM_FT_BEGIN_AT, aliveCount, blackholedCount, memberCount, diff --git a/app/src/Profile/components/BeginAtProvider.tsx b/app/src/Profile/components/BeginAtProvider.tsx new file mode 100644 index 00000000..0e58b81c --- /dev/null +++ b/app/src/Profile/components/BeginAtProvider.tsx @@ -0,0 +1,39 @@ +import { useQuery } from '@apollo/client'; +import { useParams } from 'react-router-dom'; + +import { BeginAtContext } from '@/Profile/contexts/BeginAtContext'; +import { GET_PERSONAL_GENERAL_ZERO_COST_BY_LOGIN } from '@/Profile/dashboard-contents-queries/GET_PERSONAL_GENERAL_ZERO_COST_BY_LOGIN'; +import { FullPageApolloErrorView } from '@shared/components/ApolloError/FullPageApolloErrorView'; +import { FullPageApolloNotFoundView } from '@shared/components/ApolloError/FullPageApolloNotFoundView'; + +export const BeginAtProvider = ({ children }: React.PropsWithChildren) => { + const { login } = useParams() as { login: string }; + + // FIXME: DailyActivities에서만 쓰는데 굳이 여기서 쓸 필요 없음. + const { loading, error, data } = useQuery( + GET_PERSONAL_GENERAL_ZERO_COST_BY_LOGIN, + { + variables: { login }, + }, + ); + + if (loading) { + return null; + } + if (error) { + return ; + } + if (!data) { + return ; + } + + const { beginAt } = data.getPersonalGeneral; + + return ( + + {children} + + ); +}; diff --git a/app/src/Profile/components/UserProfileProvider.tsx b/app/src/Profile/components/UserProfileProvider.tsx new file mode 100644 index 00000000..83ba5aae --- /dev/null +++ b/app/src/Profile/components/UserProfileProvider.tsx @@ -0,0 +1,33 @@ +import { useQuery } from '@apollo/client'; +import { useParams } from 'react-router-dom'; + +import { UserProfileContext } from '@/Profile/contexts/UserProfileContext'; +import { GET_USER_PROFILE_BY_LOGIN } from '@/Profile/dashboard-contents-queries/GET_USER_PROFILE_BY_LOGIN'; +import { FullPageApolloErrorView } from '@shared/components/ApolloError/FullPageApolloErrorView'; +import { FullPageApolloNotFoundView } from '@shared/components/ApolloError/FullPageApolloNotFoundView'; + +export const UserProfileProvider = ({ children }: React.PropsWithChildren) => { + const { login } = useParams() as { login: string }; + + const { loading, error, data } = useQuery(GET_USER_PROFILE_BY_LOGIN, { + variables: { login }, + }); + + if (loading) { + return null; + } + if (error) { + return ; + } + if (!data) { + return ; + } + + const { userProfile } = data.getPersonalGeneral; + + return ( + + {children} + + ); +}; diff --git a/app/src/Profile/dashboard-contents/Eval/CountRecords.tsx b/app/src/Profile/dashboard-contents/Eval/CountRecords.tsx index 30fc238e..eacaa4f9 100644 --- a/app/src/Profile/dashboard-contents/Eval/CountRecords.tsx +++ b/app/src/Profile/dashboard-contents/Eval/CountRecords.tsx @@ -1,6 +1,8 @@ import { useQuery } from '@apollo/client'; +import { differenceInCalendarMonths } from 'date-fns'; import { useContext } from 'react'; +import { BeginAtContext } from '@/Profile/contexts/BeginAtContext'; import { UserProfileContext } from '@/Profile/contexts/UserProfileContext'; import { gql } from '@shared/__generated__'; import { AreaChart } from '@shared/components/Chart'; @@ -11,6 +13,7 @@ import { DashboardContentNotFound, } from '@shared/components/DashboardContentView/Error'; import { numberWithUnitFormatter } from '@shared/utils/formatters/numberWithUnitFormatter'; +import { injectEmptyMonth } from '@shared/utils/injectEmptyMonth'; const GET_COUNT_RECORDS_BY_LOGIN = gql(/* GraphQL */ ` query GetCountRecordsByLogin($login: String!, $last: Int!) { @@ -25,12 +28,14 @@ const GET_COUNT_RECORDS_BY_LOGIN = gql(/* GraphQL */ ` export const CountRecords = () => { const { login } = useContext(UserProfileContext); + const beginAt = useContext(BeginAtContext); + const last = differenceInCalendarMonths(new Date(), beginAt) + 1; const title = '월간 평가 횟수 추이'; const { loading, error, data } = useQuery(GET_COUNT_RECORDS_BY_LOGIN, { variables: { login, - last: 12, + last, }, }); @@ -45,10 +50,14 @@ export const CountRecords = () => { } const { countRecords } = data.getPersonalEval; - const seriesData = countRecords.map(({ at, value }) => ({ - x: at, - y: value, - })); + const seriesData = injectEmptyMonth( + countRecords.map(({ at, value }) => ({ + x: new Date(at), + y: value, + })), + last, + ); + const series: ApexAxisChartSeries = [ { name: '평가 횟수', diff --git a/app/src/Profile/dashboard-contents/General/DailyActivities/utils/getScoreByDailyActivityType.ts b/app/src/Profile/dashboard-contents/General/DailyActivities/utils/getScoreByDailyActivityType.ts index 0370f526..ae9ca2c0 100644 --- a/app/src/Profile/dashboard-contents/General/DailyActivities/utils/getScoreByDailyActivityType.ts +++ b/app/src/Profile/dashboard-contents/General/DailyActivities/utils/getScoreByDailyActivityType.ts @@ -1,6 +1,6 @@ import { - DailyActivityType, DailyActivityRecord, + DailyActivityType, } from '@shared/__generated__/graphql'; import { MINUTES } from '@shared/constants/date'; diff --git a/app/src/Profile/dashboard-contents/LogtimeAndProject/LevelRecords.tsx b/app/src/Profile/dashboard-contents/LogtimeAndProject/LevelRecords.tsx index ccbe7b39..c777ee98 100644 --- a/app/src/Profile/dashboard-contents/LogtimeAndProject/LevelRecords.tsx +++ b/app/src/Profile/dashboard-contents/LogtimeAndProject/LevelRecords.tsx @@ -124,6 +124,14 @@ const LevelRecordsChart = ({ series }: LevelRecordsChartProps) => { }; const options: ApexCharts.ApexOptions = { + chart: { + toolbar: { + show: false, + tools: { + zoom: false, + }, + }, + }, colors: [ theme.colors.chart.primary.default, theme.colors.mono.gray500, diff --git a/app/src/Profile/dashboard-contents/LogtimeAndProject/LogtimeRecords.tsx b/app/src/Profile/dashboard-contents/LogtimeAndProject/LogtimeRecords.tsx index b1396a9e..35e92d00 100644 --- a/app/src/Profile/dashboard-contents/LogtimeAndProject/LogtimeRecords.tsx +++ b/app/src/Profile/dashboard-contents/LogtimeAndProject/LogtimeRecords.tsx @@ -1,6 +1,8 @@ import { useQuery } from '@apollo/client'; +import { differenceInCalendarMonths } from 'date-fns'; import { useContext } from 'react'; +import { BeginAtContext } from '@/Profile/contexts/BeginAtContext'; import { UserProfileContext } from '@/Profile/contexts/UserProfileContext'; import { gql } from '@shared/__generated__'; import { AreaChart } from '@shared/components/Chart'; @@ -11,6 +13,7 @@ import { DashboardContentNotFound, } from '@shared/components/DashboardContentView/Error'; import { numberWithUnitFormatter } from '@shared/utils/formatters/numberWithUnitFormatter'; +import { injectEmptyMonth } from '@shared/utils/injectEmptyMonth'; const GET_LOGTIME_RECORDS_BY_LOGIN = gql(/* GraphQL */ ` query GetLogtimeRecords($login: String!, $last: Int!) { @@ -25,12 +28,14 @@ const GET_LOGTIME_RECORDS_BY_LOGIN = gql(/* GraphQL */ ` export const LogtimeRecords = () => { const { login } = useContext(UserProfileContext); + const beginAt = useContext(BeginAtContext); + const last = differenceInCalendarMonths(new Date(), beginAt) + 1; const title = '월간 접속 시간 추이'; const { loading, error, data } = useQuery(GET_LOGTIME_RECORDS_BY_LOGIN, { variables: { login, - last: 12, + last, }, }); @@ -45,10 +50,13 @@ export const LogtimeRecords = () => { } const { logtimeRecords } = data.getPersonalGeneral; - const seriesData = logtimeRecords.map(({ at, value }) => ({ - x: at, - y: value, - })); + const seriesData = injectEmptyMonth( + logtimeRecords.map(({ at, value }) => ({ + x: new Date(at), + y: value, + })), + last, + ); const series: ApexAxisChartSeries = [ { name: '접속 시간', diff --git a/app/src/Profile/dashboard-contents/Versus/LevelRecords.tsx b/app/src/Profile/dashboard-contents/Versus/LevelRecords.tsx index 46e64f9f..24a2cf36 100644 --- a/app/src/Profile/dashboard-contents/Versus/LevelRecords.tsx +++ b/app/src/Profile/dashboard-contents/Versus/LevelRecords.tsx @@ -115,6 +115,14 @@ const LevelRecordsChart = ({ series }: LevelRecordsChartProps) => { }; const options: ApexCharts.ApexOptions = { + chart: { + toolbar: { + show: false, + tools: { + zoom: false, + }, + }, + }, colors: [ theme.colors.chart.primary.default, theme.colors.chart.accent.default, diff --git a/app/src/Profile/index.tsx b/app/src/Profile/index.tsx index 32a0c943..8b392b9a 100644 --- a/app/src/Profile/index.tsx +++ b/app/src/Profile/index.tsx @@ -1,74 +1,58 @@ -import { useQuery } from '@apollo/client'; import { useAtomValue } from 'jotai'; import { Outlet, useLocation, useParams } from 'react-router-dom'; +import { BeginAtProvider } from '@/Profile/components/BeginAtProvider'; import { UserProfile } from '@/Profile/components/UserProfile'; -import { UserProfileContext } from '@/Profile/contexts/UserProfileContext'; -import { GET_USER_PROFILE_BY_LOGIN } from '@/Profile/dashboard-contents-queries/GET_USER_PROFILE_BY_LOGIN'; +import { UserProfileProvider } from '@/Profile/components/UserProfileProvider'; import { userAtom } from '@shared/atoms/userAtom'; -import { FullPageApolloErrorView } from '@shared/components/ApolloError/FullPageApolloErrorView'; -import { FullPageApolloNotFoundView } from '@shared/components/ApolloError/FullPageApolloNotFoundView'; import { ROUTES } from '@shared/constants/routes'; import { Tab, Tabs, VStack } from '@shared/ui-kit'; const ProfileLayout = () => { const { pathname } = useLocation(); const { login } = useParams() as { login: string }; - const { loading, error, data } = useQuery(GET_USER_PROFILE_BY_LOGIN, { - variables: { login }, - }); const user = useAtomValue(userAtom); - if (loading) { - return null; - } - if (error) { - return ; - } - if (!data) { - return ; - } - - const { userProfile } = data.getPersonalGeneral; - return ( - - - - - - 일반 - - - 접속 · 과제 - - - 평가 - - {login !== user.login ? ( + + + + + + + 일반 + + + 접속 · 과제 + - 나와 비교 + 평가 - ) : null} - - - - + {login !== user.login ? ( + + 나와 비교 + + ) : null} + + + + + ); }; diff --git a/app/src/Profile/pages/General/index.tsx b/app/src/Profile/pages/General/index.tsx index bde774b9..a401959d 100644 --- a/app/src/Profile/pages/General/index.tsx +++ b/app/src/Profile/pages/General/index.tsx @@ -1,9 +1,6 @@ -import { useQuery } from '@apollo/client'; import { useContext } from 'react'; -import { BeginAtContext } from '@/Profile/contexts/BeginAtContext'; import { UserProfileContext } from '@/Profile/contexts/UserProfileContext'; -import { GET_PERSONAL_GENERAL_ZERO_COST_BY_LOGIN } from '@/Profile/dashboard-contents-queries/GET_PERSONAL_GENERAL_ZERO_COST_BY_LOGIN'; import { profileGeneralPageDashboardContents } from '@/Profile/dashboard-frames/profileGeneralPageDashboardContents'; import { profileGeneralPageDashboardRows } from '@/Profile/dashboard-frames/profileGeneralPageDashboardRows'; import { Footer } from '@core/components/Footer'; @@ -16,23 +13,9 @@ const ProfileGeneralPage = () => { const { login } = useContext(UserProfileContext); const device = useDeviceType(); - // FIXME: DailyActivities에서만 쓰는데 굳이 여기서 쓸 필요 없음. - const { data } = useQuery(GET_PERSONAL_GENERAL_ZERO_COST_BY_LOGIN, { - variables: { login }, - }); - - if (!data) { - return null; // FIXME: handling - } - - const { beginAt } = data.getPersonalGeneral; - return ( <> - {device !== 'mobile' ? ( { rows={profileGeneralPageDashboardMobileRows} /> )} -