Skip to content

Commit

Permalink
feat: dashboard page (#116)
Browse files Browse the repository at this point in the history
* feat: dashboard chart components

* impl: add testing

* feat: test

* feat: test chart components

* feat: feedback line chart

* feat: issue api

* feat: searched filter chart

* feat: chart bar color

* feat: issue rank scollable

* feat: refactoring line chart

* feat: chart refactoring

* feat: chart refactoring

* fix: chart point

* fix: card slider

* feat: dashboard update

* feat: update color

* feat: issue ratio fixed

* feat: issue rank parse int

* fix: react date picker

* fix: dashbaord icon, tooltip

* feat: tooltip bottom

* feat: i18n

* feat: remove test in ui
  • Loading branch information
chiol authored Dec 27, 2023
1 parent 02fb9e7 commit 57ca439
Show file tree
Hide file tree
Showing 114 changed files with 4,156 additions and 524 deletions.
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

yarn install
yarn typecheck
yarn format
yarn lint
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
"source.fixAll.eslint": "explicit"
},
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import type { ConfigServiceType } from '@/types/config-service.type';
auth: username && password && { user: username, pass: password },
secure: port === 465,
},
defaults: { from: `"User feedback" <${sender}>` },
defaults: { from: `"User feedback" <${sender}>`, sdd: '' },
template: {
dir: __dirname + '/templates/',
adapter: new HandlebarsAdapter(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,33 @@
import { ApiProperty } from '@nestjs/swagger';
import { Expose, plainToInstance } from 'class-transformer';

export class FindCountByDateByIssueResponseDto {
class IssueStatisticData {
@ApiProperty()
@Expose()
date: Date;

@ApiProperty()
@Expose()
feedbackCount: number;
}
class IssueStatistic {
@ApiProperty()
@Expose()
id: number;

@ApiProperty()
@Expose()
issues: {
id: number;
name: string;
statistics: { date: Date; count: number };
}[];
name: string;

@ApiProperty({ type: [IssueStatisticData] })
@Expose()
statistics: IssueStatisticData[];
}

export class FindCountByDateByIssueResponseDto {
@ApiProperty({ type: [IssueStatistic] })
@Expose()
issues: IssueStatistic[];

public static transform(params: any): FindCountByDateByIssueResponseDto {
return plainToInstance(FindCountByDateByIssueResponseDto, params, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,19 @@ export class FeedbackIssueStatisticsController {
private readonly feedbackIssueStatisticsService: FeedbackIssueStatisticsService,
) {}

@ApiOkResponse({ type: [FindCountByDateByIssueResponseDto] })
@ApiOkResponse({ type: FindCountByDateByIssueResponseDto })
@Get()
async getCountByDateByIssue(
@Query('from') from: Date,
@Query('to') to: Date,
@Query('interval') interval: 'day' | 'week' | 'month',
@Query('issueIds') issueIds: string,
) {
const issueIdsArray = issueIds.split(',').map((v) => parseInt(v, 10));
const issueIdsArray = issueIds
.split(',')
.map((v) => parseInt(v, 10))
.filter((v) => !isNaN(v));

return FindCountByDateByIssueResponseDto.transform(
await this.feedbackIssueStatisticsService.getCountByDateByIssue({
from,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,33 @@
import { ApiProperty } from '@nestjs/swagger';
import { Expose, plainToInstance } from 'class-transformer';

export class FindCountByDateByChannelResponseDto {
class StatisticData {
@ApiProperty()
@Expose()
date: Date;

@ApiProperty()
@Expose()
count: number;
}
class ChannelStatisticData {
@ApiProperty()
@Expose()
id: number;

@ApiProperty()
@Expose()
channels: {
id: number;
name: string;
statistics: { date: Date; count: number };
}[];
name: string;

@ApiProperty({ type: [StatisticData] })
@Expose()
statistics: StatisticData[];
}

export class FindCountByDateByChannelResponseDto {
@ApiProperty({ type: [ChannelStatisticData] })
@Expose()
channels: ChannelStatisticData[];

public static transform(params: any): FindCountByDateByChannelResponseDto {
return plainToInstance(FindCountByDateByChannelResponseDto, params, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,19 @@ export class FeedbackStatisticsController {
private readonly feedbackStatisticsService: FeedbackStatisticsService,
) {}

@ApiOkResponse({ type: [FindCountByDateByChannelResponseDto] })
@ApiOkResponse({ type: FindCountByDateByChannelResponseDto })
@Get()
async getCountByDateByChannel(
@Query('from') from: Date,
@Query('to') to: Date,
@Query('interval') interval: 'day' | 'week' | 'month',
@Query('channelIds') channelIds: string,
) {
const channelIdsArray = channelIds.split(',').map((v) => parseInt(v, 10));
const channelIdsArray = channelIds
.split(',')
.map((v) => parseInt(v, 10))
.filter((v) => !isNaN(v));

return FindCountByDateByChannelResponseDto.transform(
await this.feedbackStatisticsService.getCountByDateByChannel({
from,
Expand All @@ -48,7 +52,7 @@ export class FeedbackStatisticsController {
);
}

@ApiOkResponse({ type: [FindCountResponseDto] })
@ApiOkResponse({ type: FindCountResponseDto })
@Get('/count')
async getCount(
@Query('from') from: Date,
Expand All @@ -64,7 +68,7 @@ export class FeedbackStatisticsController {
);
}

@ApiOkResponse({ type: [FindIssuedRateResponseDto] })
@ApiOkResponse({ type: FindIssuedRateResponseDto })
@Get('/issued-ratio')
async getIssuedRatio(
@Query('from') from: Date,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,20 @@
import { ApiProperty } from '@nestjs/swagger';
import { Expose, plainToInstance } from 'class-transformer';

export class FindCountByDateResponseDto {
class IssueStatistics {
@ApiProperty()
@Expose()
date: string;

@ApiProperty()
@Expose()
statistics: {
date: string;
count: number;
}[];
count: number;
}

export class FindCountByDateResponseDto {
@ApiProperty({ type: [IssueStatistics] })
@Expose()
statistics: IssueStatistics[];

public static transform(params: any): FindCountByDateResponseDto {
return plainToInstance(FindCountByDateResponseDto, params, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,20 @@
import { ApiProperty } from '@nestjs/swagger';
import { Expose, plainToInstance } from 'class-transformer';

export class FindCountByStatusResponseDto {
class IssueStatusStatistics {
@ApiProperty()
@Expose()
status: string;

@ApiProperty()
@Expose()
statistics: {
status: string;
count: number;
}[];
count: number;
}

export class FindCountByStatusResponseDto {
@ApiProperty({ type: [IssueStatusStatistics] })
@Expose()
statistics: IssueStatusStatistics[];

public static transform(params: any): FindCountByStatusResponseDto {
return plainToInstance(FindCountByStatusResponseDto, params, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class IssueStatisticsController {
private readonly issueStatisticsService: IssueStatisticsService,
) {}

@ApiOkResponse({ type: [FindCountResponseDto] })
@ApiOkResponse({ type: FindCountResponseDto })
@Get('/count')
async getCount(
@Query('from') from: Date,
Expand All @@ -45,7 +45,7 @@ export class IssueStatisticsController {
);
}

@ApiOkResponse({ type: [FindCountByDateResponseDto] })
@ApiOkResponse({ type: FindCountByDateResponseDto })
@Get('/count-by-date')
async getCountByDate(
@Query('from') from: Date,
Expand All @@ -63,7 +63,7 @@ export class IssueStatisticsController {
);
}

@ApiOkResponse({ type: [FindCountByStatusResponseDto] })
@ApiOkResponse({ type: FindCountByStatusResponseDto })
@Get('/count-by-status')
async getCountByStatus(@Query('projectId') projectId: number) {
return FindCountByStatusResponseDto.transform(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export class IssueStatisticsService {
.groupBy('issue.status')
.getRawMany()
.then((res) =>
res.map((stat) => ({ status: stat.status, count: stat.count })),
res.map((stat) => ({ status: stat.status, count: +stat.count })),
),
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import type { SendMailDto } from './send-mail.dto';
@Injectable()
export class EmailVerificationMailingService {
private readonly baseUrl: string;

constructor(
private readonly mailerService: MailerService,
private readonly configService: ConfigService<ConfigServiceType>,
Expand Down
2 changes: 1 addition & 1 deletion apps/web/.prettierignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
src/types/api.type.ts
src/types/api.type.ts
9 changes: 2 additions & 7 deletions apps/web/jest.config.mjs
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
import nextJest from 'next/jest.js';

const createJestConfig = nextJest({
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
dir: './',
});
const createJestConfig = nextJest({ dir: './' });

// Add any custom config to be passed to Jest
/** @type {import('jest').Config} */
const jestConfig = {
// if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work
moduleDirectories: ['node_modules', '<rootDir>/'],
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
testEnvironment: 'jest-environment-jsdom',
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
'dnd-core': 'dnd-core-cjs',
},
transform: {
'^.+\\.(t|j)sx?$': '@swc/jest',
Expand Down
22 changes: 22 additions & 0 deletions apps/web/jest.setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Copyright 2023 LINE Corporation
*
* LINE Corporation licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
import '@testing-library/jest-dom';

jest.mock('react-i18next', () => ({
useTranslation: () => {
return { t: (str) => str };
},
}));
3 changes: 2 additions & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"immer": "^10.0.3",
"iron-session": "^6.3.1",
"jwt-decode": "^3.1.2",
"next": "^13.5.6",
"next": "^14.0.3",
"next-i18next": "^14.0.3",
"pino": "^8.16.0",
"react": "^18.2.0",
Expand All @@ -62,6 +62,7 @@
"react-i18next": "^13.3.1",
"react-select": "^5.7.7",
"react-use": "^17.4.0",
"recharts": "^2.10.1",
"sharp": "^0.32.6",
"tailwind-scrollbar-hide": "^1.1.7",
"zod": "^3.22.4",
Expand Down
Loading

0 comments on commit 57ca439

Please sign in to comment.