diff --git a/apps/dashboard/src/screens/dashboard/ContactBubble.tsx b/apps/dashboard/src/screens/dashboard/ContactBubble.tsx index 6a2b8c922..f80dd5579 100644 --- a/apps/dashboard/src/screens/dashboard/ContactBubble.tsx +++ b/apps/dashboard/src/screens/dashboard/ContactBubble.tsx @@ -10,7 +10,7 @@ import { } from "@/components/ui/drawer" import { Separator } from "@/components/ui/separator" import { useDashboard } from "@/shared/hooks/useDashboard" -import { X } from "lucide-react" +import { MessageCircleQuestion, X } from "lucide-react" export function ContactBubble() { const { data } = useDashboard() @@ -23,10 +23,16 @@ export function ContactBubble() { return ( -
+
+
+ +
diff --git a/apps/dashboard/src/screens/dashboard/screen.tsx b/apps/dashboard/src/screens/dashboard/screen.tsx index c201e5fc9..9374557a8 100644 --- a/apps/dashboard/src/screens/dashboard/screen.tsx +++ b/apps/dashboard/src/screens/dashboard/screen.tsx @@ -11,15 +11,22 @@ import { getTimelinePhaseMessage } from "@/screens/dashboard/timeline_steps" import { LogoutButton } from "@/shared/LogoutButton" import { Timeline } from "@/shared/Timeline" import { useDashboard } from "@/shared/hooks/useDashboard" +import { useDates } from "@/shared/hooks/useDates" import { selectForms } from "@/store/form/form_selectors" import { cx } from "@/utils/cx" import LoadingAnimation from "@/utils/loading_animation/loading_animation" -import { BadgeInfo } from "lucide-react" +import { AlertTriangle, BadgeInfo, CheckCircle } from "lucide-react" +import { DateTime } from "luxon" import { useSelector } from "react-redux" import { DashboardError } from "./DashboardError" import FormCard from "./FormCard" export function DashboardScreen() { + const { + data: dates, + isLoading: isLoadingDates, + isError: isErrorDates + } = useDates() const { data, isLoading, isError } = useDashboard() const forms = useSelector(selectForms) @@ -31,12 +38,12 @@ export function DashboardScreen() { "text-emerald-400": companyProgress <= 1 } */ - if (isLoading) { + if (isLoading || isLoadingDates) { return } // Check if root error - if (isError || data == null) { + if (isError || isErrorDates || data == null || dates == null) { return } @@ -44,6 +51,8 @@ export function DashboardScreen() { isFormVisible(formMeta.key, data.type ?? null) ) + const timelinePhaseAlert = getTimelinePhaseMessage(data.type) + return (
@@ -66,13 +75,19 @@ export function DashboardScreen() { )} - {getTimelinePhaseMessage(data.type) != null && ( + {timelinePhaseAlert != null && ( - + {timelinePhaseAlert.variant == null || + timelinePhaseAlert.variant === "info" ? ( + + ) : timelinePhaseAlert.variant === "success" ? ( + + ) : ( + + )} - {getTimelinePhaseMessage(data.type) - ?.title ?? ( + {timelinePhaseAlert?.title ?? ( Current step:{" "} {data.type.split("_").join(" ")} @@ -81,10 +96,7 @@ export function DashboardScreen() { - { - getTimelinePhaseMessage(data.type) - ?.description - } + {timelinePhaseAlert?.description} )} @@ -131,7 +143,10 @@ export function DashboardScreen() { "initial_registration", "after_initial_registration" ], - title: "Initial Registration" + title: "Initial Registration", + badgeText: DateTime.fromISO( + dates.ir.start + ).toFormat("MMM d") }, { id: [ @@ -142,9 +157,13 @@ export function DashboardScreen() { }, { id: [ - /* "complete_registration_ir_unsigned", */ + "after_initial_registration_acceptance_accepted" + /* "after_initial_registration_acceptance_rejected" */ ], - title: "You got a spot at the fair" + title: "You got a spot at the fair", + badgeText: DateTime.fromISO( + dates.ir.acceptance + ).toFormat("MMM d") }, { id: [ @@ -153,7 +172,9 @@ export function DashboardScreen() { "complete_registration_signed" ], title: "Final registration", - badgeText: "Aug 20" + badgeText: DateTime.fromISO( + dates.fr.start + ).toFormat("MMM d") }, { id: [], @@ -161,7 +182,17 @@ export function DashboardScreen() { }, { id: [], - title: "The fair 🥳" + title: "The fair 🥳", + badgeText: DateTime.fromISO( + dates.fair.days.reduce( + (acc, curr) => + DateTime.fromISO(acc) < + DateTime.fromISO(curr) + ? acc + : curr, + dates.fair.days[0] + ) + ).toFormat("MMM d") } ]} current={data.type} diff --git a/apps/dashboard/src/screens/dashboard/timeline_steps.ts b/apps/dashboard/src/screens/dashboard/timeline_steps.ts index 6f4bb73df..3d67078bb 100644 --- a/apps/dashboard/src/screens/dashboard/timeline_steps.ts +++ b/apps/dashboard/src/screens/dashboard/timeline_steps.ts @@ -6,13 +6,14 @@ export const TIMELINE_STEPS: Partial< { title?: string description: string + variant?: "info" | "success" | "warning" // Default info } > > = { before_initial_registration: { title: "This year's fair is still under development", description: - "We haven't finalized this year's contract yet, come back later..." + "We're still working on the initial registration, come back later..." }, initial_registration: { title: "Welcome to Armada!", @@ -20,16 +21,31 @@ export const TIMELINE_STEPS: Partial< "To get a spot in this year's event, please complete the initial registration" }, initial_registration_signed: { - title: "You have signed this year's contract", - description: "We'll be in touch!" + title: "You have completed this year's initial registration", + description: + "We'll be in touch! Feel free to add additional information about your company", + variant: "success" }, after_initial_registration: { title: "You did not complete the initial registration", - description: "All hope is not lost! Please contact our sales team" + description: "All hope is not lost! Please contact our sales team", + variant: "warning" }, after_initial_registration_signed: { - title: "You have signed this year's contract", - description: "We'll be in touch!" + title: "You have completed this year's initial registration", + description: "We'll be in touch!", + variant: "success" + }, + after_initial_registration_acceptance_accepted: { + title: "You got a spot at the fair", + description: "We'll be in touch with more information", + variant: "success" + }, + after_initial_registration_acceptance_rejected: { + title: "We are at full capacity", + description: + "Unfortunately, we are unable to offer you a spot at the fair, if any spot appears we will contact you", + variant: "warning" }, complete_registration_ir_signed: { title: "Welcome to the Armada final registration!", @@ -39,12 +55,14 @@ export const TIMELINE_STEPS: Partial< complete_registration_ir_unsigned: { title: "Welcome to the Armada final registration!", description: - "You have not signed an initial contract with us and can therefore not proceed with the final registration process until this is resolved" + "You have not completed the initial registration, please contact our sales team", + variant: "warning" }, complete_registration_signed: { title: "You have completed the final registration", description: - "Please make sure to fill in the remaining cards. See you at the fair!" + "Please make sure to fill in the remaining cards. See you at the fair!", + variant: "success" } } diff --git a/apps/dashboard/src/shared/Timeline.tsx b/apps/dashboard/src/shared/Timeline.tsx index 7f33b287d..0b46b5a16 100644 --- a/apps/dashboard/src/shared/Timeline.tsx +++ b/apps/dashboard/src/shared/Timeline.tsx @@ -53,13 +53,30 @@ export function Timeline( >
{stage.badgeText != null && ( currentIndex + } + )} > {stage.badgeText} )} -

+

currentIndex + } + )} + > {stage.title}

diff --git a/apps/dashboard/src/shared/hooks/useDashboard.tsx b/apps/dashboard/src/shared/hooks/useDashboard.tsx index c9aa4152a..3ed079081 100644 --- a/apps/dashboard/src/shared/hooks/useDashboard.tsx +++ b/apps/dashboard/src/shared/hooks/useDashboard.tsx @@ -68,7 +68,7 @@ export interface Company { export async function queryDashboard() { const response = await fetch(`${HOST}/api/dashboard`) const result = (await response.json()) as DashboardResponse - console.log("REGISTRATION", JSON.stringify(result)) + result.type = "after_initial_registration_acceptance_accepted" return result } diff --git a/apps/dashboard/src/shared/hooks/useDates.tsx b/apps/dashboard/src/shared/hooks/useDates.tsx new file mode 100644 index 000000000..ad29af442 --- /dev/null +++ b/apps/dashboard/src/shared/hooks/useDates.tsx @@ -0,0 +1,42 @@ +import { HOST } from "@/shared/vars" +import { useQuery } from "@tanstack/react-query" + +export interface DatesResponse { + fair: Fair + ticket: Ticket + ir: Ir + fr: Fr +} + +export interface Fair { + description: string + days: string[] // Dates +} + +export interface Ticket { + end: string // Date - after this date companies will no longer be able to modify their lunch or banquet tickets +} + +export interface Ir { + start: string // Date + end: string // Date + acceptance: string // Date - At this date companies will be informed if they got a spot at the fair +} + +export interface Fr { + start: string // Date + end: string // Date +} + +export async function queryDates() { + const response = await fetch(`${HOST}/api/dates`) + const data = await response.json() + return data as DatesResponse +} + +export function useDates() { + return useQuery({ + queryKey: ["dates"], + queryFn: queryDates + }) +} diff --git a/apps/dashboard/src/shared/useLoadData.tsx b/apps/dashboard/src/shared/useLoadData.tsx index 64f5f24ae..bd4209862 100644 --- a/apps/dashboard/src/shared/useLoadData.tsx +++ b/apps/dashboard/src/shared/useLoadData.tsx @@ -35,7 +35,6 @@ export default function useLoadData() { fetch(`${HOST}/api/dashboard/`, {}).then(async raw => { const data = await raw.json() - console.log("DATA #", JSON.stringify(data)) if (data.error != null) { dispatch(setErrors(data.error)) diff --git a/apps/dashboard/src/store/company/company_slice.ts b/apps/dashboard/src/store/company/company_slice.ts index 00e6f2d07..2ba521184 100644 --- a/apps/dashboard/src/store/company/company_slice.ts +++ b/apps/dashboard/src/store/company/company_slice.ts @@ -6,6 +6,8 @@ export type RegistrationStatus = | "initial_registration_signed" | "after_initial_registration" | "after_initial_registration_signed" // The time period between initial registration and complete registration + | "after_initial_registration_acceptance_accepted" // Past the "acceptance date", if company not marked as accepted, it is rejected + | "after_initial_registration_acceptance_rejected" // Past the "acceptance date", is rejected | "before_complete_registration_ir_unsigned" | "before_complete_registration_ir_signed" | "complete_registration_ir_unsigned"