From a85ab8da892c5dce25f3adc84dbdd29cbfbe9e83 Mon Sep 17 00:00:00 2001 From: Hampus Hallkvist Date: Thu, 22 Feb 2024 17:03:02 +0100 Subject: [PATCH] feat: Add timeline --- apps/dashboard/package.json | 2 +- apps/dashboard/pnpm-lock.yaml | 56 +++--- apps/dashboard/src/components/ui/sonner.tsx | 2 + .../src/screens/dashboard/DashboardError.tsx | 20 +- .../src/screens/dashboard/screen.tsx | 173 +++++++++++------- apps/dashboard/src/shared/Timeline.tsx | 61 ++++++ 6 files changed, 214 insertions(+), 100 deletions(-) create mode 100644 apps/dashboard/src/shared/Timeline.tsx diff --git a/apps/dashboard/package.json b/apps/dashboard/package.json index a178fcb82..85c6edba5 100644 --- a/apps/dashboard/package.json +++ b/apps/dashboard/package.json @@ -56,7 +56,7 @@ "eslint-plugin-react-refresh": "^0.4.3", "postcss": "^8.4.27", "tailwindcss": "^3.3.3", - "typescript": "^5.0.2", + "typescript": "5.4.0-beta", "vite": "^4.4.5" } } diff --git a/apps/dashboard/pnpm-lock.yaml b/apps/dashboard/pnpm-lock.yaml index 8f1320373..e3d9a8782 100644 --- a/apps/dashboard/pnpm-lock.yaml +++ b/apps/dashboard/pnpm-lock.yaml @@ -108,10 +108,10 @@ devDependencies: version: 18.2.7 '@typescript-eslint/eslint-plugin': specifier: ^6.0.0 - version: 6.0.0(@typescript-eslint/parser@6.0.0)(eslint@8.45.0)(typescript@5.0.2) + version: 6.0.0(@typescript-eslint/parser@6.0.0)(eslint@8.45.0)(typescript@5.4.0-beta) '@typescript-eslint/parser': specifier: ^6.0.0 - version: 6.0.0(eslint@8.45.0)(typescript@5.0.2) + version: 6.0.0(eslint@8.45.0)(typescript@5.4.0-beta) '@vitejs/plugin-react': specifier: ^4.0.3 version: 4.0.3(vite@4.4.5) @@ -134,8 +134,8 @@ devDependencies: specifier: ^3.3.3 version: 3.3.3 typescript: - specifier: ^5.0.2 - version: 5.0.2 + specifier: 5.4.0-beta + version: 5.4.0-beta vite: specifier: ^4.4.5 version: 4.4.5(@types/node@20.11.19) @@ -1488,7 +1488,7 @@ packages: resolution: {integrity: sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==} dev: false - /@typescript-eslint/eslint-plugin@6.0.0(@typescript-eslint/parser@6.0.0)(eslint@8.45.0)(typescript@5.0.2): + /@typescript-eslint/eslint-plugin@6.0.0(@typescript-eslint/parser@6.0.0)(eslint@8.45.0)(typescript@5.4.0-beta): resolution: {integrity: sha512-xuv6ghKGoiq856Bww/yVYnXGsKa588kY3M0XK7uUW/3fJNNULKRfZfSBkMTSpqGG/8ZCXCadfh8G/z/B4aqS/A==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -1500,10 +1500,10 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.6.2 - '@typescript-eslint/parser': 6.0.0(eslint@8.45.0)(typescript@5.0.2) + '@typescript-eslint/parser': 6.0.0(eslint@8.45.0)(typescript@5.4.0-beta) '@typescript-eslint/scope-manager': 6.0.0 - '@typescript-eslint/type-utils': 6.0.0(eslint@8.45.0)(typescript@5.0.2) - '@typescript-eslint/utils': 6.0.0(eslint@8.45.0)(typescript@5.0.2) + '@typescript-eslint/type-utils': 6.0.0(eslint@8.45.0)(typescript@5.4.0-beta) + '@typescript-eslint/utils': 6.0.0(eslint@8.45.0)(typescript@5.4.0-beta) '@typescript-eslint/visitor-keys': 6.0.0 debug: 4.3.4 eslint: 8.45.0 @@ -1513,13 +1513,13 @@ packages: natural-compare: 1.4.0 natural-compare-lite: 1.4.0 semver: 7.5.4 - ts-api-utils: 1.0.1(typescript@5.0.2) - typescript: 5.0.2 + ts-api-utils: 1.0.1(typescript@5.4.0-beta) + typescript: 5.4.0-beta transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@6.0.0(eslint@8.45.0)(typescript@5.0.2): + /@typescript-eslint/parser@6.0.0(eslint@8.45.0)(typescript@5.4.0-beta): resolution: {integrity: sha512-TNaufYSPrr1U8n+3xN+Yp9g31vQDJqhXzzPSHfQDLcaO4tU+mCfODPxCwf4H530zo7aUBE3QIdxCXamEnG04Tg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -1531,11 +1531,11 @@ packages: dependencies: '@typescript-eslint/scope-manager': 6.0.0 '@typescript-eslint/types': 6.0.0 - '@typescript-eslint/typescript-estree': 6.0.0(typescript@5.0.2) + '@typescript-eslint/typescript-estree': 6.0.0(typescript@5.4.0-beta) '@typescript-eslint/visitor-keys': 6.0.0 debug: 4.3.4 eslint: 8.45.0 - typescript: 5.0.2 + typescript: 5.4.0-beta transitivePeerDependencies: - supports-color dev: true @@ -1548,7 +1548,7 @@ packages: '@typescript-eslint/visitor-keys': 6.0.0 dev: true - /@typescript-eslint/type-utils@6.0.0(eslint@8.45.0)(typescript@5.0.2): + /@typescript-eslint/type-utils@6.0.0(eslint@8.45.0)(typescript@5.4.0-beta): resolution: {integrity: sha512-ah6LJvLgkoZ/pyJ9GAdFkzeuMZ8goV6BH7eC9FPmojrnX9yNCIsfjB+zYcnex28YO3RFvBkV6rMV6WpIqkPvoQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -1558,12 +1558,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.0.0(typescript@5.0.2) - '@typescript-eslint/utils': 6.0.0(eslint@8.45.0)(typescript@5.0.2) + '@typescript-eslint/typescript-estree': 6.0.0(typescript@5.4.0-beta) + '@typescript-eslint/utils': 6.0.0(eslint@8.45.0)(typescript@5.4.0-beta) debug: 4.3.4 eslint: 8.45.0 - ts-api-utils: 1.0.1(typescript@5.0.2) - typescript: 5.0.2 + ts-api-utils: 1.0.1(typescript@5.4.0-beta) + typescript: 5.4.0-beta transitivePeerDependencies: - supports-color dev: true @@ -1573,7 +1573,7 @@ packages: engines: {node: ^16.0.0 || >=18.0.0} dev: true - /@typescript-eslint/typescript-estree@6.0.0(typescript@5.0.2): + /@typescript-eslint/typescript-estree@6.0.0(typescript@5.4.0-beta): resolution: {integrity: sha512-2zq4O7P6YCQADfmJ5OTDQTP3ktajnXIRrYAtHM9ofto/CJZV3QfJ89GEaM2BNGeSr1KgmBuLhEkz5FBkS2RQhQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -1588,13 +1588,13 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.4 - ts-api-utils: 1.0.1(typescript@5.0.2) - typescript: 5.0.2 + ts-api-utils: 1.0.1(typescript@5.4.0-beta) + typescript: 5.4.0-beta transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@6.0.0(eslint@8.45.0)(typescript@5.0.2): + /@typescript-eslint/utils@6.0.0(eslint@8.45.0)(typescript@5.4.0-beta): resolution: {integrity: sha512-SOr6l4NB6HE4H/ktz0JVVWNXqCJTOo/mHnvIte1ZhBQ0Cvd04x5uKZa3zT6tiodL06zf5xxdK8COiDvPnQ27JQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -1605,7 +1605,7 @@ packages: '@types/semver': 7.5.0 '@typescript-eslint/scope-manager': 6.0.0 '@typescript-eslint/types': 6.0.0 - '@typescript-eslint/typescript-estree': 6.0.0(typescript@5.0.2) + '@typescript-eslint/typescript-estree': 6.0.0(typescript@5.4.0-beta) eslint: 8.45.0 eslint-scope: 5.1.1 semver: 7.5.4 @@ -3170,13 +3170,13 @@ packages: dependencies: is-number: 7.0.0 - /ts-api-utils@1.0.1(typescript@5.0.2): + /ts-api-utils@1.0.1(typescript@5.4.0-beta): resolution: {integrity: sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==} engines: {node: '>=16.13.0'} peerDependencies: typescript: '>=4.2.0' dependencies: - typescript: 5.0.2 + typescript: 5.4.0-beta dev: true /ts-interface-checker@0.1.13: @@ -3198,9 +3198,9 @@ packages: engines: {node: '>=10'} dev: true - /typescript@5.0.2: - resolution: {integrity: sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==} - engines: {node: '>=12.20'} + /typescript@5.4.0-beta: + resolution: {integrity: sha512-KgekV5JS7TQ7Bb8eO64QGxdM7MSBUUXOXq28OWX23d2MA8SiVtNYoo4s33tCTEGV8+6AGBRD2+KiXNNnexRRYw==} + engines: {node: '>=14.17'} hasBin: true dev: true diff --git a/apps/dashboard/src/components/ui/sonner.tsx b/apps/dashboard/src/components/ui/sonner.tsx index 31e21328c..a2e447150 100644 --- a/apps/dashboard/src/components/ui/sonner.tsx +++ b/apps/dashboard/src/components/ui/sonner.tsx @@ -11,6 +11,8 @@ const Toaster = ({ ...props }: ToasterProps) => { theme={theme as ToasterProps["theme"]} className="toaster group" toastOptions={{ + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore classNames: { toast: "group toast group-[.toaster]:bg-white group-[.toaster]:text-stone-950 group-[.toaster]:border-stone-200 group-[.toaster]:shadow-lg dark:group-[.toaster]:bg-stone-950 dark:group-[.toaster]:text-stone-50 dark:group-[.toaster]:border-stone-800", diff --git a/apps/dashboard/src/screens/dashboard/DashboardError.tsx b/apps/dashboard/src/screens/dashboard/DashboardError.tsx index d62011571..7dbe18c5c 100644 --- a/apps/dashboard/src/screens/dashboard/DashboardError.tsx +++ b/apps/dashboard/src/screens/dashboard/DashboardError.tsx @@ -1,7 +1,7 @@ import { useSelector } from "react-redux" -import { selectErrors } from "../../store/form/form_selectors" import { PrimaryFormHeader } from "../../forms/primary/Header" import { LogoutButton } from "../../shared/LogoutButton" +import { selectErrors } from "../../store/form/form_selectors" const ERRORS = { not_authorized: ( @@ -12,18 +12,20 @@ const ERRORS = {

), - user_did_not_sign_ir: ( -

- You have not completed Initial Registration. -

- ), + user_did_not_sign_ir:

You have not completed Initial Registration.

, user_is_not_exhibitor: (

- You did not get picked for the fair this year. + Unfortunetly we are at full captity as of right now, we might get + space for more exhibitors later and will contact you then.

), user_has_no_company:

You are not associated with any company

, - cr_not_open:

We are working on this years final registration page, please come back later!

+ cr_not_open: ( +

+ We are working on this years final registration page, please come + back later! +

+ ) } export function DashboardError() { @@ -35,7 +37,7 @@ export function DashboardError() {

Oups, something went wrong

-
{ERRORS[error]}
+
{ERRORS[error]}
) diff --git a/apps/dashboard/src/screens/dashboard/screen.tsx b/apps/dashboard/src/screens/dashboard/screen.tsx index 8258a88a9..6101756f6 100644 --- a/apps/dashboard/src/screens/dashboard/screen.tsx +++ b/apps/dashboard/src/screens/dashboard/screen.tsx @@ -9,6 +9,7 @@ import { isFormOpen, isFormVisible } from "@/forms/form_access" import { ContactBubble } from "@/screens/dashboard/ContactBubble" import { getTimelinePhaseMessage } from "@/screens/dashboard/timeline_steps" import { LogoutButton } from "@/shared/LogoutButton" +import { Timeline } from "@/shared/Timeline" import { useRegistration } from "@/shared/hooks/useRegistration" import { selectForms } from "@/store/form/form_selectors" import { cx } from "@/utils/cx" @@ -44,54 +45,50 @@ export function DashboardScreen() { ) return ( -
-
{/* SIDEBAR */}
-
-
-
-
-

- {data.company.name} -

-
- {data.contact?.first_name != null && ( - - - - Welcome {data.contact.first_name}! - - - From this dashboard you will be able to - configure your Armada experience. You will - be able to provide information, buy products - and read about our procedures - - - - )} - {getTimelinePhaseMessage(data.type) != null && ( - - - - - {getTimelinePhaseMessage(data.type) - ?.title ?? ( - - Current step:{" "} - {data.type.split("_").join(" ")} - - )} - - - - { - getTimelinePhaseMessage(data.type) - ?.description - } - - - )} - {/*
+
+
+
{/* SIDEBAR */}
+
+
+ {data.contact?.first_name != null && ( + + + + Welcome {data.contact.first_name} + ! + + + From this dashboard you will be able to + configure your Armada experience. You + will be able to provide information, buy + products and read about our procedures + + + + )} + {getTimelinePhaseMessage(data.type) != null && ( + + + + + {getTimelinePhaseMessage(data.type) + ?.title ?? ( + + Current step:{" "} + {data.type.split("_").join(" ")} + + )} + + + + { + getTimelinePhaseMessage(data.type) + ?.description + } + + + )} + {/*

{companyProgress < 1 ? "Company Progress" @@ -105,24 +102,76 @@ export function DashboardScreen() { )}

*/} -
- {formCardsData.map(([key, formMeta]) => ( - - ))} +
+ {formCardsData.map(([key, formMeta]) => ( + + ))} +
+
+ +
-
- -
{/* Spacer */} +
+ {companyContact != null && ( -
+
)} diff --git a/apps/dashboard/src/shared/Timeline.tsx b/apps/dashboard/src/shared/Timeline.tsx new file mode 100644 index 000000000..6420e0be9 --- /dev/null +++ b/apps/dashboard/src/shared/Timeline.tsx @@ -0,0 +1,61 @@ +import { Badge } from "@/components/ui/badge" +import { RegistrationStatus } from "@/store/company/company_slice" +import { cx } from "@/utils/cx" + +export interface TimelineStage { + id: RegistrationStatus | RegistrationStatus[] + title: string + badgeText?: string +} + +export function Timeline( + props: { + stages: TimelineStage[] + current: RegistrationStatus + } & React.HTMLProps +) { + const { stages, current, className, ...rest } = props + + const currentIndex = stages.findIndex(stage => + Array.isArray(stage.id) + ? stage.id.includes(current) + : stage.id === current + ) + const currentPercentage = currentIndex / (stages.length - 1) + + return ( +
+
+
+ {stages.map((stage, index) => ( +
+
currentIndex + } + )} + >
+ {stage.badgeText != null && ( + + {stage.badgeText} + + )} +

+ {stage.title} +

+
+ ))} +
+
+ ) +}