diff --git a/src/apps/review/src/lib/hooks/useFetchScorecard.ts b/src/apps/review/src/lib/hooks/useFetchScorecard.ts new file mode 100644 index 000000000..963aca936 --- /dev/null +++ b/src/apps/review/src/lib/hooks/useFetchScorecard.ts @@ -0,0 +1,27 @@ +import useSWR, { SWRResponse } from 'swr' + +import { EnvironmentConfig } from '~/config' +import { xhrGetAsync } from '~/libs/core' + +import { Scorecard } from '../models' + +interface UseFetchScorecardParams { + id: string; +} +const baseUrl = `${EnvironmentConfig.API.V6}/review` + +export function useFetchScorecard( + { + id, + }: UseFetchScorecardParams, +): Scorecard { + + const fetcher = (url: string): Promise => xhrGetAsync(url) + + const { data }: SWRResponse = useSWR( + `${baseUrl}/scorecards/${id}`, + fetcher, + ) + + return data as Scorecard +} diff --git a/src/apps/review/src/lib/models/Scorecard.model.ts b/src/apps/review/src/lib/models/Scorecard.model.ts index 81c7c8f69..dd40af253 100644 --- a/src/apps/review/src/lib/models/Scorecard.model.ts +++ b/src/apps/review/src/lib/models/Scorecard.model.ts @@ -2,6 +2,8 @@ * Scorecard */ +import { ScorecardGroup } from './ScorecardGroup.model' + export enum ProjectType { DEVELOPMENT = 'DEVELOPMENT', DATA_SCIENCE = 'DATA_SCIENCE', @@ -94,4 +96,9 @@ export interface Scorecard { category: string status: ScorecardStatus index?: number + version: string + challengeType: string + minScore: number + maxScore: number + scorecardGroups: ScorecardGroup[] } diff --git a/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardDetails/ScorecardDetails.module.scss b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardDetails/ScorecardDetails.module.scss new file mode 100644 index 000000000..41f8159c2 --- /dev/null +++ b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardDetails/ScorecardDetails.module.scss @@ -0,0 +1,53 @@ +.container { + display: flex; + flex-direction: row; + padding: 32px; + background-color: #F6F7F9; + margin-top: 20px; + border-radius: 8px; + .left { + display: flex; + flex: 1; + flex-direction: column; + } + + .item { + display: flex; + flex-direction: column; + margin-bottom: 20px; + .label { + font-weight: 700; + font-family: "Nunito Sans", sans-serif; + font-size: 16px; + color: #000000; + margin-bottom: 6px; + } + .value { + font-weight: 400; + font-family: "Nunito Sans", sans-serif; + font-size: 16px; + color: #0A0A0A; + text-transform: capitalize; + &.active { + color: #00797A; + } + + &.inactive, &.deleted { + color: #767676; + font-family: 'Inter', sans-serif; + font-weight: 600; + font-size: 14px; + } + } + } + + .right { + display: flex; + flex: 3; + flex-direction: column; + .item { + display: flex; + flex-direction: column; + } + } +} \ No newline at end of file diff --git a/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardDetails/ScorecardDetails.tsx b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardDetails/ScorecardDetails.tsx new file mode 100644 index 000000000..3d99c7b97 --- /dev/null +++ b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardDetails/ScorecardDetails.tsx @@ -0,0 +1,52 @@ +import { FC } from 'react' +import cn from 'classnames' + +import { ProjectTypeLabels, Scorecard, ScorecardStatusLabels, ScorecardTypeLabels } from '~/apps/review/src/lib/models' + +import styles from './ScorecardDetails.module.scss' + +interface ScorecardDetailsProps { + scorecard: Scorecard +} + +const ScorecardDetails: FC = (props: ScorecardDetailsProps) => { + const getStatusClassname = (): string => styles[ScorecardStatusLabels[props.scorecard.status]?.toLowerCase()] + return ( +
+
+
+
Version
+
{props.scorecard.version}
+
+
+
Type
+
{ScorecardTypeLabels[props.scorecard.type]}
+
+
+
Project Type
+
{ProjectTypeLabels[props.scorecard.challengeTrack]}
+
+
+
+
+
Category
+
{props.scorecard.challengeType}
+
+
+
Status
+
+ {ScorecardStatusLabels[props.scorecard.status]} +
+
+
+
Min - Max. Score
+
{`${props.scorecard.minScore} - ${props.scorecard.maxScore}`}
+
+
+
+ ) +} + +export default ScorecardDetails diff --git a/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardDetails/index.ts b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardDetails/index.ts new file mode 100644 index 000000000..51a168df3 --- /dev/null +++ b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardDetails/index.ts @@ -0,0 +1 @@ +export { default as ScorecardDetails } from './ScorecardDetails' diff --git a/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardGroups/ScorecardGroups.module.scss b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardGroups/ScorecardGroups.module.scss new file mode 100644 index 000000000..0ab9472a5 --- /dev/null +++ b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardGroups/ScorecardGroups.module.scss @@ -0,0 +1,48 @@ +@import '@libs/ui/styles/includes'; + +.container { + margin-top: 32px; + .group { + .heading { + padding: 12px 16px; + background-color: #0F172A; + color: #ffffff; + display: flex; + flex-direction: column; + border-top-left-radius: 8px; + border-top-right-radius: 8px; + .groupNumber { + font-size: 14px; + font-family: "Nunito Sans", sans-serif; + font-weight: 400; + } + .groupInfo { + display: flex; + flex-direction: row; + font-size: 16px; + font-family: "Nunito Sans", sans-serif; + margin-top: 4px; + .name { + display: flex; + flex: 1; + font-weight: 700; + } + } + } + } +} + +@media (max-width: #{$lg-max}) { + .container { + .group { + .heading { + .groupInfo { + flex-direction: column; + .name { + margin-bottom: 8px; + } + } + } + } + } +} \ No newline at end of file diff --git a/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardGroups/ScorecardGroups.tsx b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardGroups/ScorecardGroups.tsx new file mode 100644 index 000000000..8d96dc65b --- /dev/null +++ b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardGroups/ScorecardGroups.tsx @@ -0,0 +1,32 @@ +import { FC } from 'react' + +import { ScorecardGroup } from '~/apps/review/src/lib/models' + +import ScorecardSections from '../ScorecardSections/ScorecardSections' + +import styles from './ScorecardGroups.module.scss' + +interface ScorecardGroupsProps { + groups: ScorecardGroup[] +} + +const ScorecardGroups: FC = (props: ScorecardGroupsProps) => ( +
+ { + props.groups.map((group, index) => ( +
+
+
{`Group ${index + 1}`}
+
+
{group.name}
+
{group.weight}
+
+
+ +
+ )) + } +
+) + +export default ScorecardGroups diff --git a/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardGroups/index.ts b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardGroups/index.ts new file mode 100644 index 000000000..dedd1564e --- /dev/null +++ b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardGroups/index.ts @@ -0,0 +1 @@ +export { default as ScorecardGroups } from './ScorecardGroups' diff --git a/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardSections/ScorecardSections.module.scss b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardSections/ScorecardSections.module.scss new file mode 100644 index 000000000..c3142a557 --- /dev/null +++ b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardSections/ScorecardSections.module.scss @@ -0,0 +1,107 @@ +@import '@libs/ui/styles/includes'; + +.container { + background-color: #E0E4E84D; + padding: 40px 32px; + .section { + .heading { + padding: 12px 16px; + background-color: #00797A; + color: #ffffff; + display: flex; + flex-direction: column; + border-top-left-radius: 8px; + border-top-right-radius: 8px; + .sectionInfo { + display: flex; + flex-direction: row; + margin-top: 4px; + font-size: 16px; + font-family: "Nunito Sans", sans-serif; + .name { + display: flex; + flex: 1; + font-weight: 700; + } + } + } + .questions { + background-color: #FFFFFF; + padding: 32px 20px; + .question { + background-color: #F6F7F9; + padding: 20px 16px; + display: flex; + flex-direction: row; + color: #0A0A0A; + margin-bottom: 0px; + &.notLast { + margin-bottom: 20px; + } + .left { + display: flex; + flex: 4; + flex-direction: column; + .description { + font-weight: 700; + font-size: 16px; + } + .detailItemsWrapper { + margin-top: 16px; + .detailItem { + display: flex; + flex-direction: row; + font-family: "Nunito Sans", sans-serif; + margin-bottom: 8px; + .label { + font-weight: 700; + font-size: 14px; + min-width: 142px; + } + .value { + font-weight: 400; + font-size: 14px; + } + } + } + } + .right { + display: flex; + flex: 1; + justify-content: flex-end; + } + } + } + } +} + +@media (max-width: #{$lg-max}) { + .container { + .section { + .heading { + .sectionInfo { + flex-direction: column; + .name { + margin-bottom: 4px; + } + } + } + .questions { + .question { + flex-direction: column; + .left { + .detailItemsWrapper { + .detailItem { + flex-direction: column; + min-width: auto; + } + } + } + .right { + justify-content: flex-start; + } + } + } + } + } +} \ No newline at end of file diff --git a/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardSections/ScorecardSections.tsx b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardSections/ScorecardSections.tsx new file mode 100644 index 000000000..0c35f2be8 --- /dev/null +++ b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardSections/ScorecardSections.tsx @@ -0,0 +1,70 @@ +import { FC } from 'react' +import cn from 'classnames' + +import { ScorecardSection } from '~/apps/review/src/lib/models' + +import styles from './ScorecardSections.module.scss' + +interface ScorecardSectionsProps { + sections: ScorecardSection[] +} + +const ScorecardSections: FC = (props: ScorecardSectionsProps) => ( +
+ { + props.sections.map((section, sectionIndex) => ( +
+
+
{`Section ${sectionIndex + 1}`}
+
+
{section.name}
+
{section.weight}
+
+
+
+ { + section.questions.map((question, index) => ( +
+
+
+ {`${sectionIndex + 1}.${index + 1} ${question.description}`} +
+
+
+
Guidelines:
+
{question.guidelines}
+
+
+
Scale:
+
+ {`Scale ${question.scaleMin} - ${question.scaleMax}`} +
+
+
+
Document Upload:
+ {/* This will be added once upload functionality works */} +
NA
+
+
+
+
+
{question.weight}
+
+
+ )) + } +
+
+ )) + } +
+) + +export default ScorecardSections diff --git a/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardSections/index.ts b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardSections/index.ts new file mode 100644 index 000000000..e326e1290 --- /dev/null +++ b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ScorecardSections/index.ts @@ -0,0 +1 @@ +export { default as ScorecardSections } from './ScorecardSections' diff --git a/src/apps/review/src/pages/scorecards/ViewScorecardPage/ViewScorecardPage.module.scss b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ViewScorecardPage.module.scss index e69de29bb..7fc297673 100644 --- a/src/apps/review/src/pages/scorecards/ViewScorecardPage/ViewScorecardPage.module.scss +++ b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ViewScorecardPage.module.scss @@ -0,0 +1,14 @@ +.container { + padding: 32px 0; + .section { + &.evaluationStructureSection { + margin-top: 54px; + } + .heading { + font-weight: 700; + font-size: 24px; + color: #0A0A0A; + line-height: 30px; + } + } +} \ No newline at end of file diff --git a/src/apps/review/src/pages/scorecards/ViewScorecardPage/ViewScorecardPage.tsx b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ViewScorecardPage.tsx index 1de00f221..7632a2cba 100644 --- a/src/apps/review/src/pages/scorecards/ViewScorecardPage/ViewScorecardPage.tsx +++ b/src/apps/review/src/pages/scorecards/ViewScorecardPage/ViewScorecardPage.tsx @@ -1,7 +1,66 @@ -import { FC } from 'react' +import { FC, useContext, useMemo } from 'react' +import { useParams } from 'react-router-dom' +import cn from 'classnames' -const ViewScorecardPage: FC = () => ( -
View scorecard
-) +import { PencilIcon } from '@heroicons/react/solid' +import { Button } from '~/libs/ui' +import { profileContext, ProfileContextData, UserRole } from '~/libs/core' + +import { PageWrapper } from '../../../lib' +import { useFetchScorecard } from '../../../lib/hooks/useFetchScorecard' + +import { ScorecardDetails } from './ScorecardDetails' +import { ScorecardGroups } from './ScorecardGroups' +import styles from './ViewScorecardPage.module.scss' + +const PencilIconWrapper: FC = () => + +const ViewScorecardPage: FC = () => { + const { scorecardId = '' }: { scorecardId?: string } = useParams<{ scorecardId: string }>() + const { profile }: ProfileContextData = useContext(profileContext) + const isAdmin = profile?.roles.includes(UserRole.administrator) + const breadCrumb = useMemo( + () => [{ index: 1, label: 'Scorecards', path: '/review/scorecard' }, { index: 2, label: 'Scorecards Details' }], + [], + ) + + const scorecard = useFetchScorecard({ id: scorecardId as string }) + + return ( + + Edit Scorecard + + )} + > + { + scorecard && ( +
+
+

1. Scorecard Information

+ {scorecard && } +
+ { + scorecard.scorecardGroups.length > 0 && ( +
+

2. Evaluation Structure

+ +
+ ) + } +
+ ) + } +
+ ) +} export default ViewScorecardPage diff --git a/src/apps/review/src/review-app.routes.tsx b/src/apps/review/src/review-app.routes.tsx index f508a8c4d..baf3fa3d1 100644 --- a/src/apps/review/src/review-app.routes.tsx +++ b/src/apps/review/src/review-app.routes.tsx @@ -57,9 +57,9 @@ export const toolTitle: string = ToolTitle.review export const reviewRoutes: ReadonlyArray = [ // Review App Root { - authRequired: true, children: [ { + authRequired: true, element: , route: '', }, @@ -67,11 +67,13 @@ export const reviewRoutes: ReadonlyArray = [ { children: [ { + authRequired: true, element: , id: 'active-reviews-page', route: '', }, { + authRequired: true, children: [ { element: , @@ -83,7 +85,6 @@ export const reviewRoutes: ReadonlyArray = [ id: 'scorecard-details-page', route: 'scorecard-details/:scorecardId', }, - ], element: , id: challengeDetailRouteId, @@ -97,11 +98,13 @@ export const reviewRoutes: ReadonlyArray = [ { children: [ { + authRequired: true, element: , id: 'list-scorecards-page', route: '', }, { + authRequired: false, element: , id: 'view-scorecard-page', route: ':scorecardId', diff --git a/src/libs/core/lib/router/router-context/router.context-provider.tsx b/src/libs/core/lib/router/router-context/router.context-provider.tsx index 97f89e93d..aa083bcc8 100644 --- a/src/libs/core/lib/router/router-context/router.context-provider.tsx +++ b/src/libs/core/lib/router/router-context/router.context-provider.tsx @@ -100,6 +100,7 @@ export const RouterProvider: FC = (props: RouterProviderPro function getRouteElement(route: PlatformRoute): JSX.Element { + console.log(route, 'route') // create the route element const routeElement: JSX.Element = !route.authRequired ? route.element