From 91fb21e5a47defd717323db74abbeab0f2b7a465 Mon Sep 17 00:00:00 2001 From: Justin Gasper Date: Tue, 15 Apr 2025 15:10:28 +1000 Subject: [PATCH 01/83] Deploy this branch --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 933f28cfa..1672b5f95 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -221,6 +221,7 @@ workflows: - dev - LVT-256 - CORE-635 + - feat/review - deployQa: context: org-global From 35ae08daeb3b38c4a5e80c8ce9755ad35dbf74a3 Mon Sep 17 00:00:00 2001 From: billsedison Date: Mon, 28 Apr 2025 14:25:40 +0800 Subject: [PATCH 02/83] Design update and member flow --- src/apps/review/src/ReviewApp.tsx | 3 +- src/apps/review/src/config/index.config.ts | 16 +- .../src/lib/assets/icons/editor/bold.ts | 4 +- .../src/lib/assets/icons/editor/code.ts | 4 +- .../src/lib/assets/icons/editor/heading-1.ts | 7 +- .../src/lib/assets/icons/editor/heading-2.ts | 4 +- .../src/lib/assets/icons/editor/heading-3.ts | 4 +- .../src/lib/assets/icons/editor/image.ts | 7 +- .../src/lib/assets/icons/editor/italic.ts | 4 +- .../src/lib/assets/icons/editor/link.ts | 13 +- .../src/lib/assets/icons/editor/mentions.ts | 5 +- .../lib/assets/icons/editor/ordered-list.ts | 4 +- .../src/lib/assets/icons/editor/quote.ts | 7 +- .../lib/assets/icons/editor/strikethrough.ts | 4 +- .../src/lib/assets/icons/editor/table.ts | 7 +- .../lib/assets/icons/editor/unordered-list.ts | 7 +- .../lib/assets/icons/editor/upload-file.ts | 4 +- .../src/lib/assets/icons/external-link.svg | 4 +- .../review/src/lib/assets/icons/icon-1st.svg | 5 + .../review/src/lib/assets/icons/icon-2nd.svg | 6 + .../review/src/lib/assets/icons/icon-3rd.svg | 5 + .../src/lib/assets/icons/icon-appeal.svg | 10 + .../src/lib/assets/icons/icon-error.svg | 3 + .../src/lib/assets/icons/icon-event.svg | 10 + .../review/src/lib/assets/icons/icon-file.svg | 10 + .../src/lib/assets/icons/icon-handle.svg | 3 + .../src/lib/assets/icons/icon-reopen.svg | 3 + .../src/lib/assets/icons/icon-review.svg | 3 + .../src/lib/assets/icons/icon-submission.svg | 10 + .../src/lib/assets/icons/icon-timer.svg | 10 + .../src/lib/assets/icons/icon-upload.svg | 3 + .../src/lib/assets/icons/icon-warning.svg | 3 + src/apps/review/src/lib/assets/icons/index.ts | 5 +- .../review/src/lib/assets/icons/selector.svg | 9 +- .../lib/components/Appeal/Appeal.module.scss | 75 +++++ .../src/lib/components/Appeal/Appeal.tsx | 115 ++++++++ .../review/src/lib/components/Appeal/index.ts | 1 + .../AppealComment/AppealComment.module.scss | 45 ++- .../AppealComment/AppealComment.tsx | 39 ++- .../BreadCrumb/BreadCrumb.module.scss | 30 ++ .../lib/components/BreadCrumb/BreadCrumb.tsx | 28 ++ .../src/lib/components/BreadCrumb/index.ts | 1 + .../ChallengeDetailsContent.tsx | 49 +++- .../ChallengeLinks/ChallengeLinks.module.scss | 13 +- .../ChallengeLinks/ChallengeLinks.tsx | 4 +- .../ChallengePhaseInfo.module.scss | 46 ++- .../ChallengePhaseInfo/ChallengePhaseInfo.tsx | 66 ++++- .../ConfirmModal/ConfirmModal.module.scss | 28 +- .../components/ConfirmModal/ConfirmModal.tsx | 74 ++++- .../FieldMarkdownEditor.module.scss | 61 ++-- .../FieldMarkdownEditor.tsx | 104 ++++--- .../FieldSelect/FieldSelect.module.scss | 11 +- .../components/FieldSelect/FieldSelect.tsx | 36 ++- .../lib/components/Layout/Layout.module.scss | 4 +- .../src/lib/components/Layout/Layout.tsx | 21 +- .../MarkdownReview/MarkdownReview.module.scss | 5 +- .../components/NavTabs/NavTabs.module.scss | 106 ++++++- .../src/lib/components/NavTabs/NavTabs.tsx | 81 ++++-- .../PageWrapper/PageWrapper.module.scss | 19 +- .../components/PageWrapper/PageWrapper.tsx | 6 +- .../ProgressBar/ProgressBar.module.scss | 32 ++ .../components/ProgressBar/ProgressBar.tsx | 35 +++ .../src/lib/components/ProgressBar/index.ts | 1 + .../ScorecardDetails.module.scss | 100 +++++-- .../ScorecardDetails/ScorecardDetails.tsx | 274 +++++++++++------- .../ScorecardDetailsHeader.module.scss | 21 +- .../ScorecardDetailsHeader.tsx | 37 +-- .../ScorecardQuestionEdit.module.scss | 158 +++++++--- .../ScorecardQuestionEdit.tsx | 264 ++++++++++------- .../ScorecardQuestionView.module.scss | 123 ++++++-- .../ScorecardQuestionView.tsx | 117 ++++++-- .../SubmissionBarInfo.module.scss | 51 ++++ .../SubmissionBarInfo/SubmissionBarInfo.tsx | 77 +++++ .../lib/components/SubmissionBarInfo/index.ts | 1 + .../TableActiveReviews.module.scss | 23 ++ .../TableActiveReviews/TableActiveReviews.tsx | 73 ++++- .../TableRegistration.module.scss | 15 + .../TableRegistration/TableRegistration.tsx | 72 +++-- .../TableReviewAppeals.module.scss | 30 ++ .../TableReviewAppeals/TableReviewAppeals.tsx | 110 ++++--- ...TableReviewAppealsForSubmitter.module.scss | 73 +++++ .../TableReviewAppealsForSubmitter.tsx | 178 ++++++++++++ .../TableReviewAppealsForSubmitter/index.ts | 1 + .../TableSubmissionScreening.module.scss | 22 ++ .../TableSubmissionScreening.tsx | 114 +++++--- .../TableWinners/TableWinners.module.scss | 21 ++ .../components/TableWinners/TableWinners.tsx | 130 +++++---- .../src/lib/components/Tabs/Tabs.module.scss | 77 ++++- .../review/src/lib/components/Tabs/Tabs.tsx | 67 +++-- src/apps/review/src/lib/hooks/index.ts | 1 + .../src/lib/hooks/useFetchChallengeInfo.ts | 37 ++- .../review/src/lib/hooks/useFetchReviews.ts | 8 +- src/apps/review/src/lib/hooks/useRole.ts | 16 + .../review/src/lib/models/BreadCrumb.model.ts | 5 + .../src/lib/models/ChallengeInfo.model.ts | 3 + .../review/src/lib/models/Screening.model.ts | 12 + .../src/lib/models/SelectOption.model.ts | 4 + .../src/lib/models/SubmissionInfo.model.ts | 2 + src/apps/review/src/lib/models/index.ts | 3 + .../src/lib/services/challenges.service.ts | 6 +- src/apps/review/src/lib/services/index.ts | 1 + .../src/lib/services/screening.service.ts | 14 + .../src/lib/services/submissions.service.ts | 32 +- src/apps/review/src/lib/styles/index.scss | 183 +++++++++++- src/apps/review/src/lib/utils/finalScore.ts | 8 + src/apps/review/src/lib/utils/index.ts | 1 + src/apps/review/src/lib/utils/time.ts | 7 +- .../review/src/mock-datas/MockChallenges.ts | 12 + .../src/mock-datas/MockProjectResults.ts | 88 +++++- .../src/mock-datas/MockRegistrations.ts | 10 +- .../review/src/mock-datas/MockScreening.ts | 80 +++++ .../src/mock-datas/MockSubmissionReviews.ts | 43 +++ .../review/src/mock-datas/MockSubmissions.ts | 98 ++++++- src/apps/review/src/mock-datas/index.ts | 1 + .../ActiveReviewAssigments.tsx | 2 +- .../ActiveReviewsPage.module.scss | 24 +- .../ActiveReviewsPage/ActiveReviewsPage.tsx | 55 ++-- .../ChallengeDetailsPage.module.scss | 41 ++- .../ChallengeDetailsPage.tsx | 65 ++++- .../ScorecardDetailsPage.module.scss | 7 + .../ScorecardDetailsPage.tsx | 63 +++- 121 files changed, 3551 insertions(+), 952 deletions(-) create mode 100644 src/apps/review/src/lib/assets/icons/icon-1st.svg create mode 100644 src/apps/review/src/lib/assets/icons/icon-2nd.svg create mode 100644 src/apps/review/src/lib/assets/icons/icon-3rd.svg create mode 100644 src/apps/review/src/lib/assets/icons/icon-appeal.svg create mode 100644 src/apps/review/src/lib/assets/icons/icon-error.svg create mode 100644 src/apps/review/src/lib/assets/icons/icon-event.svg create mode 100644 src/apps/review/src/lib/assets/icons/icon-file.svg create mode 100644 src/apps/review/src/lib/assets/icons/icon-handle.svg create mode 100644 src/apps/review/src/lib/assets/icons/icon-reopen.svg create mode 100644 src/apps/review/src/lib/assets/icons/icon-review.svg create mode 100644 src/apps/review/src/lib/assets/icons/icon-submission.svg create mode 100644 src/apps/review/src/lib/assets/icons/icon-timer.svg create mode 100644 src/apps/review/src/lib/assets/icons/icon-upload.svg create mode 100644 src/apps/review/src/lib/assets/icons/icon-warning.svg create mode 100644 src/apps/review/src/lib/components/Appeal/Appeal.module.scss create mode 100644 src/apps/review/src/lib/components/Appeal/Appeal.tsx create mode 100644 src/apps/review/src/lib/components/Appeal/index.ts create mode 100644 src/apps/review/src/lib/components/BreadCrumb/BreadCrumb.module.scss create mode 100644 src/apps/review/src/lib/components/BreadCrumb/BreadCrumb.tsx create mode 100644 src/apps/review/src/lib/components/BreadCrumb/index.ts create mode 100644 src/apps/review/src/lib/components/ProgressBar/ProgressBar.module.scss create mode 100644 src/apps/review/src/lib/components/ProgressBar/ProgressBar.tsx create mode 100644 src/apps/review/src/lib/components/ProgressBar/index.ts create mode 100644 src/apps/review/src/lib/components/SubmissionBarInfo/SubmissionBarInfo.module.scss create mode 100644 src/apps/review/src/lib/components/SubmissionBarInfo/SubmissionBarInfo.tsx create mode 100644 src/apps/review/src/lib/components/SubmissionBarInfo/index.ts create mode 100644 src/apps/review/src/lib/components/TableReviewAppealsForSubmitter/TableReviewAppealsForSubmitter.module.scss create mode 100644 src/apps/review/src/lib/components/TableReviewAppealsForSubmitter/TableReviewAppealsForSubmitter.tsx create mode 100644 src/apps/review/src/lib/components/TableReviewAppealsForSubmitter/index.ts create mode 100644 src/apps/review/src/lib/hooks/useRole.ts create mode 100644 src/apps/review/src/lib/models/BreadCrumb.model.ts create mode 100644 src/apps/review/src/lib/models/Screening.model.ts create mode 100644 src/apps/review/src/lib/models/SelectOption.model.ts create mode 100644 src/apps/review/src/lib/services/screening.service.ts create mode 100644 src/apps/review/src/lib/utils/finalScore.ts create mode 100644 src/apps/review/src/mock-datas/MockScreening.ts create mode 100644 src/apps/review/src/mock-datas/MockSubmissionReviews.ts diff --git a/src/apps/review/src/ReviewApp.tsx b/src/apps/review/src/ReviewApp.tsx index 66f25fc70..4d378af2b 100644 --- a/src/apps/review/src/ReviewApp.tsx +++ b/src/apps/review/src/ReviewApp.tsx @@ -12,8 +12,7 @@ import './lib/styles/index.scss' const ReviewApp: FC = () => { const { getChildRoutes }: RouterContextData = useContext(routerContext) - // eslint-disable-next-line react-hooks/exhaustive-deps -- missing dependency: getChildRoutes - const childRoutes = useMemo(() => getChildRoutes(toolTitle), []) + const childRoutes = useMemo(() => getChildRoutes(toolTitle), [getChildRoutes]) useEffect(() => { document.body.classList.add('review-app') diff --git a/src/apps/review/src/config/index.config.ts b/src/apps/review/src/config/index.config.ts index c1365d4c0..be7aa7c5d 100644 --- a/src/apps/review/src/config/index.config.ts +++ b/src/apps/review/src/config/index.config.ts @@ -2,9 +2,9 @@ * Common config for ui. */ -import { InputSelectOption } from '~/libs/ui' +import { SelectOption } from '../lib/models' -export const CHALLENGE_TYPE_SELECT_OPTIONS: InputSelectOption[] = [ +export const CHALLENGE_TYPE_SELECT_OPTIONS: SelectOption[] = [ { label: 'All', value: '', @@ -20,10 +20,10 @@ export const CHALLENGE_TYPE_SELECT_OPTIONS: InputSelectOption[] = [ 'Other', ].map(item => ({ label: item, value: item })), ] -export const QUESTION_YES_NO_OPTIONS: InputSelectOption[] = ['Yes', 'No'].map( +export const QUESTION_YES_NO_OPTIONS: SelectOption[] = ['Yes', 'No'].map( item => ({ label: item, value: item }), ) -export const QUESTION_RESPONSE_OPTIONS: InputSelectOption[] = [ +export const QUESTION_RESPONSE_OPTIONS: SelectOption[] = [ { label: 'Comment', value: 'COMMENT', @@ -45,3 +45,11 @@ export const QUESTION_RESPONSE_TYPE_MAPPING_DISPLAY: { [key: string]: string } } export const TABLE_DATE_FORMAT = 'MMM DD, HH:mm A' export const THRESHOLD_SHORT_TIME = 2 * 60 * 60 * 1000 // in miliseconds + +export const ORDINAL_SUFFIX = new Map([[1, '1st'], [2, '2nd'], [3, '3rd']]) + +export const REVIEWER = 'Reviewer' +export const SUBMITTER = 'Submitter' + +export const MOCKHANDLE = 'stevenfrog' +export const REVIEWCOUNT = 3 diff --git a/src/apps/review/src/lib/assets/icons/editor/bold.ts b/src/apps/review/src/lib/assets/icons/editor/bold.ts index 424a7d281..412e6b6a1 100644 --- a/src/apps/review/src/lib/assets/icons/editor/bold.ts +++ b/src/apps/review/src/lib/assets/icons/editor/bold.ts @@ -1,3 +1,5 @@ /* eslint-disable max-len */ export const IconBold -= '' += ` + +` diff --git a/src/apps/review/src/lib/assets/icons/editor/code.ts b/src/apps/review/src/lib/assets/icons/editor/code.ts index 5de1d83ed..58a2dfee4 100644 --- a/src/apps/review/src/lib/assets/icons/editor/code.ts +++ b/src/apps/review/src/lib/assets/icons/editor/code.ts @@ -1,5 +1,5 @@ /* eslint-disable max-len */ -export const IconCode = ` - +export const IconCode = ` + ` diff --git a/src/apps/review/src/lib/assets/icons/editor/heading-1.ts b/src/apps/review/src/lib/assets/icons/editor/heading-1.ts index 9d4e1b71c..60f069328 100644 --- a/src/apps/review/src/lib/assets/icons/editor/heading-1.ts +++ b/src/apps/review/src/lib/assets/icons/editor/heading-1.ts @@ -1,4 +1,5 @@ /* eslint-disable max-len */ -export const IconHeading1 = ` - -` +export const IconHeading1 = ` + + +` diff --git a/src/apps/review/src/lib/assets/icons/editor/heading-2.ts b/src/apps/review/src/lib/assets/icons/editor/heading-2.ts index 4ebde5589..fb7b4a87e 100644 --- a/src/apps/review/src/lib/assets/icons/editor/heading-2.ts +++ b/src/apps/review/src/lib/assets/icons/editor/heading-2.ts @@ -1,4 +1,4 @@ /* eslint-disable max-len */ -export const IconHeading2 = ` - +export const IconHeading2 = ` + ` diff --git a/src/apps/review/src/lib/assets/icons/editor/heading-3.ts b/src/apps/review/src/lib/assets/icons/editor/heading-3.ts index cac94bc5c..e3760e891 100644 --- a/src/apps/review/src/lib/assets/icons/editor/heading-3.ts +++ b/src/apps/review/src/lib/assets/icons/editor/heading-3.ts @@ -1,4 +1,4 @@ /* eslint-disable max-len */ -export const IconHeading3 = ` - +export const IconHeading3 = ` + ` diff --git a/src/apps/review/src/lib/assets/icons/editor/image.ts b/src/apps/review/src/lib/assets/icons/editor/image.ts index 85923791e..2e1be4f9b 100644 --- a/src/apps/review/src/lib/assets/icons/editor/image.ts +++ b/src/apps/review/src/lib/assets/icons/editor/image.ts @@ -1,4 +1,5 @@ /* eslint-disable max-len */ -export const IconImage = ` - -` +export const IconImage = ` + + +` diff --git a/src/apps/review/src/lib/assets/icons/editor/italic.ts b/src/apps/review/src/lib/assets/icons/editor/italic.ts index 2930710e9..9ac50459c 100644 --- a/src/apps/review/src/lib/assets/icons/editor/italic.ts +++ b/src/apps/review/src/lib/assets/icons/editor/italic.ts @@ -1,4 +1,4 @@ /* eslint-disable max-len */ -export const IconItalic = ` - +export const IconItalic = ` + ` diff --git a/src/apps/review/src/lib/assets/icons/editor/link.ts b/src/apps/review/src/lib/assets/icons/editor/link.ts index 4e1247681..548763d30 100644 --- a/src/apps/review/src/lib/assets/icons/editor/link.ts +++ b/src/apps/review/src/lib/assets/icons/editor/link.ts @@ -1,13 +1,4 @@ /* eslint-disable max-len */ -export const IconLink = ` - - - - - - - - - - +export const IconLink = ` + ` diff --git a/src/apps/review/src/lib/assets/icons/editor/mentions.ts b/src/apps/review/src/lib/assets/icons/editor/mentions.ts index a7b96df56..7d96251cf 100644 --- a/src/apps/review/src/lib/assets/icons/editor/mentions.ts +++ b/src/apps/review/src/lib/assets/icons/editor/mentions.ts @@ -1,3 +1,6 @@ /* eslint-disable max-len */ export const IconMentions -= '' += ` + + +` diff --git a/src/apps/review/src/lib/assets/icons/editor/ordered-list.ts b/src/apps/review/src/lib/assets/icons/editor/ordered-list.ts index 5d8a3397f..8acb5c59d 100644 --- a/src/apps/review/src/lib/assets/icons/editor/ordered-list.ts +++ b/src/apps/review/src/lib/assets/icons/editor/ordered-list.ts @@ -1,4 +1,4 @@ /* eslint-disable max-len */ -export const IconOrderedList = ` - +export const IconOrderedList = ` + ` diff --git a/src/apps/review/src/lib/assets/icons/editor/quote.ts b/src/apps/review/src/lib/assets/icons/editor/quote.ts index 3dbca3ad6..b392d284f 100644 --- a/src/apps/review/src/lib/assets/icons/editor/quote.ts +++ b/src/apps/review/src/lib/assets/icons/editor/quote.ts @@ -1,4 +1,5 @@ /* eslint-disable max-len */ -export const IconQuote = ` - -` +export const IconQuote = ` + + +` diff --git a/src/apps/review/src/lib/assets/icons/editor/strikethrough.ts b/src/apps/review/src/lib/assets/icons/editor/strikethrough.ts index 02734f693..9289d4a55 100644 --- a/src/apps/review/src/lib/assets/icons/editor/strikethrough.ts +++ b/src/apps/review/src/lib/assets/icons/editor/strikethrough.ts @@ -1,4 +1,4 @@ /* eslint-disable max-len */ -export const IconStrikethrough = ` - +export const IconStrikethrough = ` + ` diff --git a/src/apps/review/src/lib/assets/icons/editor/table.ts b/src/apps/review/src/lib/assets/icons/editor/table.ts index e9820a787..544a5a0a4 100644 --- a/src/apps/review/src/lib/assets/icons/editor/table.ts +++ b/src/apps/review/src/lib/assets/icons/editor/table.ts @@ -1,4 +1,5 @@ /* eslint-disable max-len */ -export const IconTable = ` - -` +export const IconTable = ` + + +` diff --git a/src/apps/review/src/lib/assets/icons/editor/unordered-list.ts b/src/apps/review/src/lib/assets/icons/editor/unordered-list.ts index 15a0fbad7..030f5bfc0 100644 --- a/src/apps/review/src/lib/assets/icons/editor/unordered-list.ts +++ b/src/apps/review/src/lib/assets/icons/editor/unordered-list.ts @@ -1,4 +1,5 @@ /* eslint-disable max-len */ -export const IconUnorderedList = ` - -` +export const IconUnorderedList = ` + + +` diff --git a/src/apps/review/src/lib/assets/icons/editor/upload-file.ts b/src/apps/review/src/lib/assets/icons/editor/upload-file.ts index a043fb1db..d1f68fe29 100644 --- a/src/apps/review/src/lib/assets/icons/editor/upload-file.ts +++ b/src/apps/review/src/lib/assets/icons/editor/upload-file.ts @@ -1,4 +1,4 @@ /* eslint-disable max-len */ -export const IconUploadFile = ` - +export const IconUploadFile = ` + ` diff --git a/src/apps/review/src/lib/assets/icons/external-link.svg b/src/apps/review/src/lib/assets/icons/external-link.svg index 8b094347b..cc724f815 100644 --- a/src/apps/review/src/lib/assets/icons/external-link.svg +++ b/src/apps/review/src/lib/assets/icons/external-link.svg @@ -1,3 +1,3 @@ - - + + diff --git a/src/apps/review/src/lib/assets/icons/icon-1st.svg b/src/apps/review/src/lib/assets/icons/icon-1st.svg new file mode 100644 index 000000000..0280de22d --- /dev/null +++ b/src/apps/review/src/lib/assets/icons/icon-1st.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/apps/review/src/lib/assets/icons/icon-2nd.svg b/src/apps/review/src/lib/assets/icons/icon-2nd.svg new file mode 100644 index 000000000..499794d19 --- /dev/null +++ b/src/apps/review/src/lib/assets/icons/icon-2nd.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/apps/review/src/lib/assets/icons/icon-3rd.svg b/src/apps/review/src/lib/assets/icons/icon-3rd.svg new file mode 100644 index 000000000..693ef3604 --- /dev/null +++ b/src/apps/review/src/lib/assets/icons/icon-3rd.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/apps/review/src/lib/assets/icons/icon-appeal.svg b/src/apps/review/src/lib/assets/icons/icon-appeal.svg new file mode 100644 index 000000000..6023a177b --- /dev/null +++ b/src/apps/review/src/lib/assets/icons/icon-appeal.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/apps/review/src/lib/assets/icons/icon-error.svg b/src/apps/review/src/lib/assets/icons/icon-error.svg new file mode 100644 index 000000000..28209fad0 --- /dev/null +++ b/src/apps/review/src/lib/assets/icons/icon-error.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/apps/review/src/lib/assets/icons/icon-event.svg b/src/apps/review/src/lib/assets/icons/icon-event.svg new file mode 100644 index 000000000..0bf91afc4 --- /dev/null +++ b/src/apps/review/src/lib/assets/icons/icon-event.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/apps/review/src/lib/assets/icons/icon-file.svg b/src/apps/review/src/lib/assets/icons/icon-file.svg new file mode 100644 index 000000000..1c807aa56 --- /dev/null +++ b/src/apps/review/src/lib/assets/icons/icon-file.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/apps/review/src/lib/assets/icons/icon-handle.svg b/src/apps/review/src/lib/assets/icons/icon-handle.svg new file mode 100644 index 000000000..6bbc6dcd4 --- /dev/null +++ b/src/apps/review/src/lib/assets/icons/icon-handle.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/apps/review/src/lib/assets/icons/icon-reopen.svg b/src/apps/review/src/lib/assets/icons/icon-reopen.svg new file mode 100644 index 000000000..c0edf1ae6 --- /dev/null +++ b/src/apps/review/src/lib/assets/icons/icon-reopen.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/apps/review/src/lib/assets/icons/icon-review.svg b/src/apps/review/src/lib/assets/icons/icon-review.svg new file mode 100644 index 000000000..301855daf --- /dev/null +++ b/src/apps/review/src/lib/assets/icons/icon-review.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/apps/review/src/lib/assets/icons/icon-submission.svg b/src/apps/review/src/lib/assets/icons/icon-submission.svg new file mode 100644 index 000000000..4b96fe2b4 --- /dev/null +++ b/src/apps/review/src/lib/assets/icons/icon-submission.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/apps/review/src/lib/assets/icons/icon-timer.svg b/src/apps/review/src/lib/assets/icons/icon-timer.svg new file mode 100644 index 000000000..6406d581f --- /dev/null +++ b/src/apps/review/src/lib/assets/icons/icon-timer.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/apps/review/src/lib/assets/icons/icon-upload.svg b/src/apps/review/src/lib/assets/icons/icon-upload.svg new file mode 100644 index 000000000..e6f694f54 --- /dev/null +++ b/src/apps/review/src/lib/assets/icons/icon-upload.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/apps/review/src/lib/assets/icons/icon-warning.svg b/src/apps/review/src/lib/assets/icons/icon-warning.svg new file mode 100644 index 000000000..f18f367c5 --- /dev/null +++ b/src/apps/review/src/lib/assets/icons/icon-warning.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/apps/review/src/lib/assets/icons/index.ts b/src/apps/review/src/lib/assets/icons/index.ts index bb70137c2..067315b11 100644 --- a/src/apps/review/src/lib/assets/icons/index.ts +++ b/src/apps/review/src/lib/assets/icons/index.ts @@ -1,6 +1,7 @@ import { ReactComponent as IconArrowLeft } from './arrow-left.svg' import { ReactComponent as IconExternalLink } from './external-link.svg' -import { ReactComponent as IconChevronDown } from './chevron-down.svg' +import { ReactComponent as IconChevronDown } from './selector.svg' +import { ReactComponent as IconError } from './icon-error.svg' export * from './editor/bold' export * from './editor/code' @@ -18,4 +19,4 @@ export * from './editor/table' export * from './editor/unordered-list' export * from './editor/upload-file' -export { IconArrowLeft, IconExternalLink, IconChevronDown } +export { IconArrowLeft, IconExternalLink, IconChevronDown, IconError } diff --git a/src/apps/review/src/lib/assets/icons/selector.svg b/src/apps/review/src/lib/assets/icons/selector.svg index 5fe7c73a8..724fed51a 100644 --- a/src/apps/review/src/lib/assets/icons/selector.svg +++ b/src/apps/review/src/lib/assets/icons/selector.svg @@ -1,3 +1,8 @@ - - + + + + + + + diff --git a/src/apps/review/src/lib/components/Appeal/Appeal.module.scss b/src/apps/review/src/lib/components/Appeal/Appeal.module.scss new file mode 100644 index 000000000..21ea7a3f5 --- /dev/null +++ b/src/apps/review/src/lib/components/Appeal/Appeal.module.scss @@ -0,0 +1,75 @@ +@import '@libs/ui/styles/includes'; + +.container { + display: flex; + flex-direction: column; + gap: 32px; + align-items: flex-start; + padding: $sp-2 $sp-6 0 0; + @include ltemd { + padding: $sp-2 $sp-3 $sp-4 0; + } + :global(.borderButton), + :global(.filledButton) { + font-size: 14px; + } + :global(.filledButton) { + font-size: 16px; + } +} + +.blockAppealComment { + background-color: var(--Appeal); +} + +.blockAppealResponse { + background-color: var(--TableColumn); +} + +.blockAppealResponse, +.blockAppealComment { + padding: $sp-4; + display: flex; + flex-direction: column; + gap: $sp-2; + width: 100%; +} + +.markdownEditor { + width: 100%; +} + +.textTitle { + color: var(--FontColor); + font-family: "Nunito Sans", sans-serif; + font-size: 14px; + font-weight: 700; + line-height: 20px; +} + +.blockBtns { + display: flex; + gap: 10px; + padding-top: 8px; + padding-bottom: 16px; + flex-wrap: wrap; +} + +.blockForm { + background-color: var(--TableColumn); + display: flex; + flex-direction: column; + padding: $sp-6; + gap: $sp-4; + width: 100%; + @include ltemd { + padding: $sp-4; + } + label { + color: var(--FontColor); + font-family: "Nunito Sans", sans-serif; + font-size: 16px; + font-weight: 700; + line-height: 20px; + } +} diff --git a/src/apps/review/src/lib/components/Appeal/Appeal.tsx b/src/apps/review/src/lib/components/Appeal/Appeal.tsx new file mode 100644 index 000000000..4cc7de074 --- /dev/null +++ b/src/apps/review/src/lib/components/Appeal/Appeal.tsx @@ -0,0 +1,115 @@ +/** + * AppealComment. + */ +import { FC, useCallback, useState } from 'react' +import { + Controller, + ControllerRenderProps, + useForm, + UseFormReturn, +} from 'react-hook-form' +import _, { bind } from 'lodash' +import classNames from 'classnames' + +import { yupResolver } from '@hookform/resolvers/yup' + +import { MarkdownReview } from '../MarkdownReview' +import { FieldMarkdownEditor } from '../FieldMarkdownEditor' +import { FormAppealResponse } from '../../models' +import { formAppealResponseSchema } from '../../utils' + +import styles from './Appeal.module.scss' + +interface Props { + className?: string +} + +export const AppealComment: FC = (props: Props) => { + const [appealResponse, setAppealResponse] = useState('') + const [showResponseForm, setShowResponseForm] = useState(false) + const [showAppealResponse, setShowAppealResponse] = useState(false) + + const { + handleSubmit, + control, + formState: { errors }, + }: UseFormReturn = useForm({ + defaultValues: { + response: '', + }, + mode: 'all', + resolver: yupResolver(formAppealResponseSchema), + }) + + const onSubmit = useCallback((data: FormAppealResponse) => { + setAppealResponse(data.response) + setShowResponseForm(false) + setShowAppealResponse(true) + }, []) + + return ( +
+ {showAppealResponse && ( +
+ Appeal Comment + +
+ )} + + {!showResponseForm && !showAppealResponse && ( + + )} + + {showResponseForm && ( +
+ + + }) { + return ( + + ) + }} + /> +
+ + +
+ + )} +
+ ) +} + +export default AppealComment diff --git a/src/apps/review/src/lib/components/Appeal/index.ts b/src/apps/review/src/lib/components/Appeal/index.ts new file mode 100644 index 000000000..49c0fd636 --- /dev/null +++ b/src/apps/review/src/lib/components/Appeal/index.ts @@ -0,0 +1 @@ +export { default as Appeal } from './Appeal' diff --git a/src/apps/review/src/lib/components/AppealComment/AppealComment.module.scss b/src/apps/review/src/lib/components/AppealComment/AppealComment.module.scss index 10bad02a6..4633da960 100644 --- a/src/apps/review/src/lib/components/AppealComment/AppealComment.module.scss +++ b/src/apps/review/src/lib/components/AppealComment/AppealComment.module.scss @@ -3,24 +3,35 @@ .container { display: flex; flex-direction: column; - gap: 22px; + gap: 24px; align-items: flex-start; + padding: 0 $sp-6 0 0; + @include ltemd { + padding: 0 $sp-3 $sp-4 0; + } + :global(.borderButton), + :global(.filledButton) { + font-size: 14px; + } + &:has(.blockForm) { + gap: 16px; + } } .blockAppealComment { - background-color: var(--Tertiary); + background-color: var(--Appeal); } .blockAppealResponse { - background-color: var(--VeryLightBlue); + background-color: var(--TableColumn); } .blockAppealResponse, .blockAppealComment { - padding: 20px 20px 35px; + padding: $sp-4; display: flex; flex-direction: column; - gap: 11px; + gap: $sp-2; width: 100%; } @@ -29,18 +40,36 @@ } .textTitle { - font-weight: $font-weight-semibold; + color: var(--FontColor); + font-family: "Nunito Sans", sans-serif; + font-size: 14px; + font-weight: 700; + line-height: 20px; } .blockBtns { display: flex; - gap: 24px; + gap: 10px; + padding-top: 8px; + padding-bottom: 16px; flex-wrap: wrap; } .blockForm { + background-color: var(--TableColumn); display: flex; flex-direction: column; - gap: 22px; + padding: $sp-6; + gap: $sp-4; width: 100%; + @include ltemd { + padding: $sp-4; + } + label { + color: var(--FontColor); + font-family: "Nunito Sans", sans-serif; + font-size: 16px; + font-weight: 700; + line-height: 20px; + } } diff --git a/src/apps/review/src/lib/components/AppealComment/AppealComment.tsx b/src/apps/review/src/lib/components/AppealComment/AppealComment.tsx index 785fb3bd8..11fda4f57 100644 --- a/src/apps/review/src/lib/components/AppealComment/AppealComment.tsx +++ b/src/apps/review/src/lib/components/AppealComment/AppealComment.tsx @@ -8,10 +8,9 @@ import { useForm, UseFormReturn, } from 'react-hook-form' -import _ from 'lodash' +import _, { bind } from 'lodash' import classNames from 'classnames' -import { Button } from '~/libs/ui' import { yupResolver } from '@hookform/resolvers/yup' import { MarkdownReview } from '../MarkdownReview' @@ -63,14 +62,15 @@ export const AppealComment: FC = (props: Props) => { )} {!showResponseForm && !showAppealResponse && ( - )} {showResponseForm && ( @@ -78,6 +78,7 @@ export const AppealComment: FC = (props: Props) => { className={styles.blockForm} onSubmit={handleSubmit(onSubmit)} > + = (props: Props) => { }} />
- +
)} diff --git a/src/apps/review/src/lib/components/BreadCrumb/BreadCrumb.module.scss b/src/apps/review/src/lib/components/BreadCrumb/BreadCrumb.module.scss new file mode 100644 index 000000000..0f4edded1 --- /dev/null +++ b/src/apps/review/src/lib/components/BreadCrumb/BreadCrumb.module.scss @@ -0,0 +1,30 @@ +@import '@libs/ui/styles/includes'; + +.breadcrumb { + padding-bottom: $sp-6; + ul { + align-items: center; + display: flex; + flex-wrap: wrap; + li { + font-size: 14px; + line-height: 20px; + white-space: nowrap; + a { + font-family: "Nunito Sans", sans-serif; + color: var(--GrayFontColor); + align-items: center; + display: flex; + &::after { + color: var(--GrayFontColor); + content: '/'; + padding: 0 $sp-2; + } + } + span { + font-family: "Nunito Sans", sans-serif; + color: var(--FontColor); + } + } + } +} diff --git a/src/apps/review/src/lib/components/BreadCrumb/BreadCrumb.tsx b/src/apps/review/src/lib/components/BreadCrumb/BreadCrumb.tsx new file mode 100644 index 000000000..747e3b80c --- /dev/null +++ b/src/apps/review/src/lib/components/BreadCrumb/BreadCrumb.tsx @@ -0,0 +1,28 @@ +import { FC } from 'react' +import { Link } from 'react-router-dom' + +import { BreadCrumbData } from '../../models' + +import styles from './BreadCrumb.module.scss' + +interface Props { + list: BreadCrumbData[] +} + +export const BreadCrumb: FC = (props: Props) => ( +
+
    + {props.list.map(item => ( +
  • + {item.path ? ( + {item.label} + ) : ( + {item.label} + )} +
  • + ))} +
+
+) + +export default BreadCrumb diff --git a/src/apps/review/src/lib/components/BreadCrumb/index.ts b/src/apps/review/src/lib/components/BreadCrumb/index.ts new file mode 100644 index 000000000..51ac0f788 --- /dev/null +++ b/src/apps/review/src/lib/components/BreadCrumb/index.ts @@ -0,0 +1 @@ +export { default as BreadCrumb } from './BreadCrumb' diff --git a/src/apps/review/src/lib/components/ChallengeDetailsContent/ChallengeDetailsContent.tsx b/src/apps/review/src/lib/components/ChallengeDetailsContent/ChallengeDetailsContent.tsx index 2fbfbf031..072e4f036 100644 --- a/src/apps/review/src/lib/components/ChallengeDetailsContent/ChallengeDetailsContent.tsx +++ b/src/apps/review/src/lib/components/ChallengeDetailsContent/ChallengeDetailsContent.tsx @@ -3,18 +3,27 @@ */ import { FC } from 'react' -import { ProjectResult, RegistrationInfo, SubmissionInfo } from '../../models' +import { + ProjectResult, + RegistrationInfo, + Screening, + SubmissionInfo, +} from '../../models' import { TableRegistration } from '../TableRegistration' import { TableNoRecord } from '../TableNoRecord' import { TableSubmissionScreening } from '../TableSubmissionScreening' import { TableReviewAppeals } from '../TableReviewAppeals' import { TableWinners } from '../TableWinners' +import { useRole } from '../../hooks' +import { MOCKHANDLE, REVIEWER } from '../../../config/index.config' +import { TableReviewAppealsForSubmitter } from '../TableReviewAppealsForSubmitter' interface Props { selectedTab: number registrations: RegistrationInfo[] submissions: SubmissionInfo[] projectResults: ProjectResult[] + screening: Screening[] } export const ChallengeDetailsContent: FC = (props: Props) => { @@ -22,22 +31,34 @@ export const ChallengeDetailsContent: FC = (props: Props) => { const registrations = props.registrations const submissions = props.submissions const projectResults = props.projectResults + const { role }: { role: string } = useRole() + const screening + = role === REVIEWER + ? props.screening + : props.screening.filter(s => s.handle === MOCKHANDLE) + + if ( + !registrations.length + || !submissions.length + || !projectResults.length + || !screening.length + ) { + return + } + return ( <> - {selectedTab === 0 && registrations.length !== 0 && ( + {selectedTab === 0 ? ( - )} - {((selectedTab === 0 && registrations.length === 0) - || (selectedTab === 2 && submissions.length === 0) - || (selectedTab === 3 && projectResults.length === 0)) && ( - - )} - - {selectedTab === 1 && } - {selectedTab === 2 && submissions.length !== 0 && ( - - )} - {selectedTab === 3 && projectResults.length !== 0 && ( + ) : selectedTab === 1 ? ( + + ) : selectedTab === 2 ? ( + role === REVIEWER ? ( + + ) : ( + + ) + ) : ( )} diff --git a/src/apps/review/src/lib/components/ChallengeLinks/ChallengeLinks.module.scss b/src/apps/review/src/lib/components/ChallengeLinks/ChallengeLinks.module.scss index 3fa1ccb7d..becea5cc3 100644 --- a/src/apps/review/src/lib/components/ChallengeLinks/ChallengeLinks.module.scss +++ b/src/apps/review/src/lib/components/ChallengeLinks/ChallengeLinks.module.scss @@ -1,15 +1,8 @@ @import '@libs/ui/styles/includes'; .container { + padding-top: $sp-6; display: flex; - gap: 20px; -} - -.blockLink { - text-decoration-line: underline; - font-size: 16px; - line-height: 22px; - letter-spacing: -0.02em; - - @include font-weight-semibold; + gap: $sp-4; + flex-wrap: wrap; } diff --git a/src/apps/review/src/lib/components/ChallengeLinks/ChallengeLinks.tsx b/src/apps/review/src/lib/components/ChallengeLinks/ChallengeLinks.tsx index 15ec053d4..7e04db2b2 100644 --- a/src/apps/review/src/lib/components/ChallengeLinks/ChallengeLinks.tsx +++ b/src/apps/review/src/lib/components/ChallengeLinks/ChallengeLinks.tsx @@ -12,8 +12,8 @@ interface Props { export const ChallengeLinks: FC = (props: Props) => (
- - + +
) diff --git a/src/apps/review/src/lib/components/ChallengePhaseInfo/ChallengePhaseInfo.module.scss b/src/apps/review/src/lib/components/ChallengePhaseInfo/ChallengePhaseInfo.module.scss index 39265ee81..5ce7680fd 100644 --- a/src/apps/review/src/lib/components/ChallengePhaseInfo/ChallengePhaseInfo.module.scss +++ b/src/apps/review/src/lib/components/ChallengePhaseInfo/ChallengePhaseInfo.module.scss @@ -2,8 +2,8 @@ .container { display: flex; - gap: 48px; - margin-top: 24px; + gap: $sp-10; + margin-top: $sp-6; flex-wrap: wrap; @include ltelg { @@ -21,11 +21,45 @@ display: flex; font-size: 14px; line-height: 19px; - /* identical to box height, or 136% */ - letter-spacing: -0.02em; - gap: 5px; + + .circleWrapper { + align-items: center; + background-color: #E9ECEF; + border-radius: 50%; + height: 40px; + display: flex; + margin-right: $sp-4; + flex-shrink: 0; + justify-content: center; + width: 40px; + } strong { - @include font-weight-semibold; + align-items: center; + color: var(--FontColor); + font-family: "Nunito Sans", sans-serif; + display: flex; + font-weight: 700; + line-height: 20px; + i { + margin-right: $sp-2; + } + } + span { + color: var(--GrayFontColor); + display: block; + font-family: "Nunito Sans", sans-serif; + line-height: 20px; + } +} + +.progress { + display: block; + padding-top: 7px; + padding-left: $sp-4; + .progressText { + display: flex; + justify-content: space-between; + padding-top: 7px; } } diff --git a/src/apps/review/src/lib/components/ChallengePhaseInfo/ChallengePhaseInfo.tsx b/src/apps/review/src/lib/components/ChallengePhaseInfo/ChallengePhaseInfo.tsx index 2283ba44a..4a37a218b 100644 --- a/src/apps/review/src/lib/components/ChallengePhaseInfo/ChallengePhaseInfo.tsx +++ b/src/apps/review/src/lib/components/ChallengePhaseInfo/ChallengePhaseInfo.tsx @@ -5,6 +5,7 @@ import { FC, useMemo } from 'react' import classNames from 'classnames' import { ChallengeInfo } from '../../models' +import { ProgressBar } from '../ProgressBar' import styles from './ChallengePhaseInfo.module.scss' @@ -14,18 +15,28 @@ interface Props { } export const ChallengePhaseInfo: FC = (props: Props) => { + const PROGRESS_TYPE = 'progress' const uiItems = useMemo(() => { const data = props.challengeInfo return [ { + icon: 'icon-review', title: 'Phase', value: data.currentPhase, }, { + icon: 'icon-handle', + title: 'My Role', + value: data.role, + }, + { + icon: 'icon-event', title: 'Phase End Date', value: data.currentPhaseEndDateString, }, { + icon: 'icon-timer', + status: data.timeLeftStatus, style: { color: data.timeLeftColor, }, @@ -34,23 +45,54 @@ export const ChallengePhaseInfo: FC = (props: Props) => { }, { title: 'Review Progress', - value: data.reviewProgress - ? `${data.reviewProgress}% Completed` - : '-', + type: PROGRESS_TYPE, + value: data.reviewProgress, }, ] }, [props.challengeInfo]) return (
- {uiItems.map(item => ( -
- - {item.title} - : - - {item.value} -
- ))} + {uiItems.map(item => { + if (item.type === PROGRESS_TYPE) { + return ( +
+ +
+ Review Progress + + {item.value} + % + +
+
+ ) + } + + return ( +
+ + + +
+ {item.title} + + {item.status && } + {item.value} + +
+
+ ) + })}
) } diff --git a/src/apps/review/src/lib/components/ConfirmModal/ConfirmModal.module.scss b/src/apps/review/src/lib/components/ConfirmModal/ConfirmModal.module.scss index 3c295c38e..75fb007f3 100644 --- a/src/apps/review/src/lib/components/ConfirmModal/ConfirmModal.module.scss +++ b/src/apps/review/src/lib/components/ConfirmModal/ConfirmModal.module.scss @@ -1,4 +1,26 @@ -.bodyClassName { - margin: 0; - padding: 0; +@import "@libs/ui/styles/includes"; + +.enhancedModal { + :global(.react-responsive-modal-modal) { + box-shadow: none; + } + h3 { + color: $black-100; + font-family: 'Inter', sans-serif; + font-size: 24px; + text-transform: none; + line-height: 30px; + } + :global(.modal-body) { + color: $black-100; + font-family: 'Inter', sans-serif; + padding: $sp-10 0; + line-height: 22px; + } + .buttons { + align-items: center; + display: flex; + justify-content: flex-end; + gap: $sp-3; + } } diff --git a/src/apps/review/src/lib/components/ConfirmModal/ConfirmModal.tsx b/src/apps/review/src/lib/components/ConfirmModal/ConfirmModal.tsx index fbd73cebd..e12c943da 100644 --- a/src/apps/review/src/lib/components/ConfirmModal/ConfirmModal.tsx +++ b/src/apps/review/src/lib/components/ConfirmModal/ConfirmModal.tsx @@ -1,22 +1,72 @@ /** * Confirm Modal. */ -import { FC } from 'react' - -import { ConfirmModalProps } from '~/libs/ui/lib/components/modals/confirm/ConfirmModal' -import { ConfirmModal as ConfirmModalOriginal } from '~/libs/ui' +import { FC, useCallback } from 'react' +import Modal, { ModalProps } from 'react-responsive-modal' +import classNames from 'classnames' import styles from './ConfirmModal.module.scss' +export interface ConfirmModalProps extends ModalProps { + action?: string + onConfirm: () => void + title: string + canSave?: boolean + maxWidth?: string + isLoading?: boolean + withoutCancel?: boolean + cancelText?: string +} + export const ConfirmModal: FC = ( props: ConfirmModalProps, -) => ( - -) +) => { + const isLoading = props.isLoading + const closeHandle = props.onClose + const handleClose = useCallback(() => { + if (!isLoading) { + closeHandle() + } + }, [isLoading, closeHandle]) + return ( + +
+ {typeof props.title === 'string' ? ( +

{props.title}

+ ) : ( + props.title + )} +
+
+ {props.children} +
+
+ {!props.withoutCancel && ( + + )} + +
+
+ ) +} export default ConfirmModal diff --git a/src/apps/review/src/lib/components/FieldMarkdownEditor/FieldMarkdownEditor.module.scss b/src/apps/review/src/lib/components/FieldMarkdownEditor/FieldMarkdownEditor.module.scss index 5e5092611..e18eb4ec7 100644 --- a/src/apps/review/src/lib/components/FieldMarkdownEditor/FieldMarkdownEditor.module.scss +++ b/src/apps/review/src/lib/components/FieldMarkdownEditor/FieldMarkdownEditor.module.scss @@ -6,22 +6,11 @@ $error-line-height: 14px; .container { display: flex; flex-direction: column; - height: 366px; + height: 280px; gap: 9px; - - &.showBorder { - :global { - .CodeMirror.CodeMirror-wrap { - border-right: 1px solid var(--GrayBorder); - border-left: 1px solid var(--GrayBorder); - border-bottom: 1px solid var(--GrayBorder); - } - .editor-toolbar { - border-top: 1px solid var(--GrayBorder); - border-left: 1px solid var(--GrayBorder); - border-right: 1px solid var(--GrayBorder); - } - } + @include ltemd { + height: 280px; + gap: 0; } &.isError { @@ -55,10 +44,17 @@ $error-line-height: 14px; border-right: 1px solid white; border-left: 1px solid white; border-bottom: 1px solid white; - border-top: 1px solid var(--GrayBorder); + border-top: 1px solid var(--EditorBorder); border-bottom-left-radius: 8px; border-bottom-right-radius: 8px; - color: var(--Primary); + font-family: "Nunito Sans", sans-serif; + font-size: 14px; + color: var(--FontColor); + } + + .CodeMirror-sizer, + .CodeMirror-scroll { + min-height: unset !important; } .editor-toolbar { @@ -73,7 +69,10 @@ $error-line-height: 14px; gap: 8px; padding: 0 8px; background-color: white; - + @include ltemd { + gap: $sp-1; + padding: 0 $sp-1; + } &::after, &::before { content: none; @@ -85,28 +84,37 @@ $error-line-height: 14px; button { margin: 8px 0; - width: 32px; - height: 32px; + width: 24px; + height: 24px; display: flex; align-items: center; justify-content: center; padding: 0; - margin: 9px 0; - + min-width: 24px; + @include ltemd { + margin: $sp-1 0; + height: 24px; + width: 24px; + } &::after { content: none; } } i.separator { - border-left: 1px solid var(--GrayBorder); + border-left: 1px solid var(--EditorBorder); + @include ltemd { + margin: 0 $sp-1; + } } } .editor-statusbar { + color: var(--GrayFontColor); + font-family: "Nunito Sans", sans-serif; font-size: 14px; line-height: 19px; - padding: 9px 0 0 0; + padding: $sp-4 0 0 0; overflow: hidden; display: flex; @@ -118,9 +126,10 @@ $error-line-height: 14px; margin-left: 0; margin-right: auto; display: flex; - color: var(--Secondary); + font-family: "Nunito Sans", sans-serif; + color: var(--GrayFontColor); font-size: 14px; - line-height: 19px; + line-height: 20px; } .countOfRemainingChars { diff --git a/src/apps/review/src/lib/components/FieldMarkdownEditor/FieldMarkdownEditor.tsx b/src/apps/review/src/lib/components/FieldMarkdownEditor/FieldMarkdownEditor.tsx index c1aa2a24e..7d54a50b0 100644 --- a/src/apps/review/src/lib/components/FieldMarkdownEditor/FieldMarkdownEditor.tsx +++ b/src/apps/review/src/lib/components/FieldMarkdownEditor/FieldMarkdownEditor.tsx @@ -9,7 +9,6 @@ import classNames from 'classnames' import 'easymde/dist/easymde.min.css' import { useOnComponentDidMount } from '~/apps/admin/src/lib/hooks' -import { IconSolid } from '~/libs/ui' import { IconBold, @@ -96,6 +95,53 @@ const allowedOtherExtensions = [ 'application/vnd.openxmlformats-officedocument.presentationml.presentation', ] +const stateStrategy = { + atom: (ret: any) => { + ret.quote = true + }, + comment: (ret: any) => { + ret.code = true + }, + em: (ret: any) => { + ret.italic = true + }, + link: (ret: any) => { + ret.link = true + }, + quote: (ret: any) => { + ret.quote = true + }, + strikethrough: (ret: any) => { + ret.strikethrough = true + }, + strong: (ret: any) => { + ret.bold = true + }, + tag: (ret: any) => { + ret.image = true + }, +} + +const toggleStrategy = { + bold: (start: any, end: any) => { + const startType = start.replace(/(\*\*|__)(?![\s\S]*(\*\*|__))/, '') + const endType = end.replace(/(\*\*|__)/, '') + return { endType, startType } + }, + italic: (start: any, end: any) => { + const startType = start.replace(/(\*|_)(?![\s\S]*(\*|_))/, '') + const endType = end.replace(/(\*|_)/, '') + return { endType, startType } + }, + strikethrough: (start: any, end: any) => { + const startType = start.replace(/(\*\*|~~)(?![\s\S]*(\*\*|~~))/, '') + const endType = end.replace(/(\*\*|~~)/, '') + return { endType, startType } + }, +} + +type CodeMirrorType = keyof typeof stateStrategy | 'variable-2' + export const FieldMarkdownEditor: FC = (props: Props) => { const elementRef = useRef(null) const easyMDE = useRef(null) @@ -104,7 +150,6 @@ export const FieldMarkdownEditor: FC = (props: Props) => { * The state of CodeMirror at the given position. */ const getState = useCallback( - // eslint-disable-next-line complexity (cm: CodeMirror.Editor, posInput?: CodeMirror.Position | undefined) => { const pos = posInput || cm.getCursor('start') const stat = cm.getTokenAt(pos) @@ -114,35 +159,21 @@ export const FieldMarkdownEditor: FC = (props: Props) => { const ret: any = {} - let data + let data: CodeMirrorType let text for (let i = 0; i < types.length; i++) { - data = types[i] - if (data === 'strong') { - ret.bold = true - } else if (data === 'variable-2') { + data = types[i] as CodeMirrorType + if (data === 'variable-2') { text = cm.getLine(pos.line) if (/^\s*\d+\.\s/.test(text)) { ret['ordered-list'] = true } else { ret['unordered-list'] = true } - } else if (data === 'atom') { - ret.quote = true - } else if (data === 'em') { - ret.italic = true - } else if (data === 'quote') { - ret.quote = true - } else if (data === 'strikethrough') { - ret.strikethrough = true - } else if (data === 'comment') { - ret.code = true - } else if (data === 'link') { - ret.link = true - } else if (data === 'tag') { - ret.image = true } else if (data.match(/^header(-[1-6])?$/)) { ret[data.replace('header', 'heading')] = true + } else if (data in stateStrategy) { + stateStrategy[data](ret) } } @@ -155,7 +186,6 @@ export const FieldMarkdownEditor: FC = (props: Props) => { * Handle toggle block */ const toggleBlock = useCallback( - // eslint-disable-next-line complexity (editor: any, type: string, startChars: any, endCharsInput?: any) => { if ( /editor-preview-active/.test( @@ -180,16 +210,7 @@ export const FieldMarkdownEditor: FC = (props: Props) => { text = cm.getLine(startPoint.line) start = text.slice(0, startPoint.ch) end = text.slice(startPoint.ch) - if (type === 'bold') { - start = start.replace(/(\*\*|__)(?![\s\S]*(\*\*|__))/, '') - end = end.replace(/(\*\*|__)/, '') - } else if (type === 'italic') { - start = start.replace(/(\*|_)(?![\s\S]*(\*|_))/, '') - end = end.replace(/(\*|_)/, '') - } else if (type === 'strikethrough') { - start = start.replace(/(\*\*|~~)(?![\s\S]*(\*\*|~~))/, '') - end = end.replace(/(\*\*|~~)/, '') - } + toggleStrategy[type as keyof typeof toggleStrategy](start, end) cm.replaceRange( start + end, @@ -242,8 +263,7 @@ export const FieldMarkdownEditor: FC = (props: Props) => { cm.setSelection(startPoint, endPoint) cm.focus() }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [], + [getState], ) /** @@ -357,8 +377,7 @@ export const FieldMarkdownEditor: FC = (props: Props) => { editor.options.imageTexts.sbInit, ) }, 1000) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) + }, [updateFileTag]) /** * Reset file input @@ -483,8 +502,7 @@ export const FieldMarkdownEditor: FC = (props: Props) => { onPosition, ) } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) + }, [getState, replaceSelection]) /** * Upload image @@ -580,8 +598,7 @@ export const FieldMarkdownEditor: FC = (props: Props) => { name: file.name, url: MockUploadUrl, }) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) + }, [afterFileUploaded, beforeUploadingFile, resetFileInput]) useOnComponentDidMount(() => { easyMDE.current = new EasyMDE({ @@ -618,7 +635,9 @@ export const FieldMarkdownEditor: FC = (props: Props) => { table: [ '', // eslint-disable-next-line max-len - '\n\n| Column 1 | Column 2 | Column 3 |\n| -------- | -------- | -------- |\n| Text | Text | Text |\n\n', + '\n\n| Column 1 | Column 2 | Column 3 |\n|' + + '-------- | -------- | -------- |\n|' + + ' Text | Text | Text |\n\n', ], uploadedFile: ['[#name#](#url#)', ''], uploadedImage: ['![#name#](#url#)', ''], @@ -793,8 +812,7 @@ export const FieldMarkdownEditor: FC = (props: Props) => {