From 452d03fbac4d956964e5bd95d93176d820d73bbc Mon Sep 17 00:00:00 2001 From: bcho892 Date: Wed, 14 Aug 2024 11:47:01 +1200 Subject: [PATCH] implement required changes --- .../AdminBookingDate/AdminBookingDate.tsx | 9 ++++++- .../AdminBookingDate/BookingUserCard.tsx | 14 ++++++++++- .../AdminBookingDateDisplay.story.tsx | 21 +++++++++++++++- .../AdminBookingDateDisplay.tsx | 9 ++++--- .../WrappedAdminBookingView.tsx | 13 +++++++++- client/src/services/Admin/AdminUtils.test.ts | 16 +++++++++++- client/src/services/Admin/AdminUtils.ts | 25 +++++++++++++++++++ 7 files changed, 99 insertions(+), 8 deletions(-) diff --git a/client/src/components/composite/Admin/AdminBookingView/AdminBookingDateDisplay/AdminBookingDate/AdminBookingDate.tsx b/client/src/components/composite/Admin/AdminBookingView/AdminBookingDateDisplay/AdminBookingDate/AdminBookingDate.tsx index f5e022c4a..290559aa7 100644 --- a/client/src/components/composite/Admin/AdminBookingView/AdminBookingDateDisplay/AdminBookingDate/AdminBookingDate.tsx +++ b/client/src/components/composite/Admin/AdminBookingView/AdminBookingDateDisplay/AdminBookingDate/AdminBookingDate.tsx @@ -18,6 +18,8 @@ export interface IAdminBookingDate { /** * All of the user information associated with the date + * + * Refer to the utility type {@link BookingInfo} */ users: Readonly[] @@ -27,6 +29,11 @@ export interface IAdminBookingDate { handleUserDelete: (id: string) => void } +/** + * Used so the first user doesn't display as #1 + */ +const INDEX_OFFSET = 1 as const + /** * Component to display the available users for each date in a booking */ @@ -48,7 +55,7 @@ const AdminBookingDate = ({ return ( diff --git a/client/src/components/composite/Admin/AdminBookingView/AdminBookingDateDisplay/AdminBookingDate/BookingUserCard.tsx b/client/src/components/composite/Admin/AdminBookingView/AdminBookingDateDisplay/AdminBookingDate/BookingUserCard.tsx index ba4b48b86..a4937e0a6 100644 --- a/client/src/components/composite/Admin/AdminBookingView/AdminBookingDateDisplay/AdminBookingDate/BookingUserCard.tsx +++ b/client/src/components/composite/Admin/AdminBookingView/AdminBookingDateDisplay/AdminBookingDate/BookingUserCard.tsx @@ -2,9 +2,21 @@ import { useState } from "react" import { BookingInfo } from "./AdminBookingDate" interface IBookingUserCard { + /** + * The order of the user on the list, preferabally enumerated from a 1-index sequence + */ index: number + /** + * User with the fields specified by utility type {@link BookingInfo} + */ user: Readonly - handleDelete?: (id: string) => void + + /** + * Callback when the delete button for the user's booking is clicked + * + * @param bookingId the associated **Booking** id for the user + */ + handleDelete?: (bookingId: string) => void } const BookingUserCard = ({ index, user, handleDelete }: IBookingUserCard) => { diff --git a/client/src/components/composite/Admin/AdminBookingView/AdminBookingDateDisplay/AdminBookingDateDisplay.story.tsx b/client/src/components/composite/Admin/AdminBookingView/AdminBookingDateDisplay/AdminBookingDateDisplay.story.tsx index ab513c3cd..5f1f2588b 100644 --- a/client/src/components/composite/Admin/AdminBookingView/AdminBookingDateDisplay/AdminBookingDateDisplay.story.tsx +++ b/client/src/components/composite/Admin/AdminBookingView/AdminBookingDateDisplay/AdminBookingDateDisplay.story.tsx @@ -5,6 +5,7 @@ import { BookingInfo, IAdminBookingDate } from "./AdminBookingDate/AdminBookingDate" +import { compareStrings } from "@/services/Admin/AdminUtils" const meta: Meta = { component: AdminBookingDateDisplay @@ -25,18 +26,36 @@ const mockUser: BookingInfo = { membership: "guest" } +const mockUser2: BookingInfo = { + bookingId: "2323", + uid: "1", + first_name: "Sigma", + last_name: "Zhao", + date_of_birth: Timestamp.fromMillis(0), + phone_number: 69696969, + dietary_requirements: "nothing", + email: "lasdl@gmail.com", + membership: "guest" +} + const mockUsersArray: BookingInfo[] = [] for (let i = 0; i < 32; ++i) { mockUsersArray.push(mockUser) + mockUsersArray.push(mockUser2) } +// Reference to mutated list +const sortedMockUsersArray = mockUsersArray.sort((a, b) => + compareStrings(a.first_name, b.first_name) +) + const mockDatesArray: IAdminBookingDate[] = [] for (let i = 1; i < 30; ++i) { mockDatesArray.push({ dateString: `${i}/10/2002`, - users: mockUsersArray, + users: sortedMockUsersArray, handleUserDelete: () => {} }) } diff --git a/client/src/components/composite/Admin/AdminBookingView/AdminBookingDateDisplay/AdminBookingDateDisplay.tsx b/client/src/components/composite/Admin/AdminBookingView/AdminBookingDateDisplay/AdminBookingDateDisplay.tsx index 65a9df155..a887d1095 100644 --- a/client/src/components/composite/Admin/AdminBookingView/AdminBookingDateDisplay/AdminBookingDateDisplay.tsx +++ b/client/src/components/composite/Admin/AdminBookingView/AdminBookingDateDisplay/AdminBookingDateDisplay.tsx @@ -4,16 +4,19 @@ import AdminBookingDate, { export interface IAdminBookingDateDisplay { /** - * The list of dates to be displayed to user + * The list of dates to be displayed to user, of type {@link IAdminBookingDate} */ dates: IAdminBookingDate[] /** - * Callback to remove the booking with specified `id` from a booking date + * Callback to remove the booking with specified **booking** `id` from a booking date */ - handleDelete?: (id: string) => void + handleDelete?: (bookingId: string) => void } +/** + * Component for handling the rendering of multiple {@link AdminBookingDate} components + */ const AdminBookingDateDisplay = ({ dates }: IAdminBookingDateDisplay) => { return (
diff --git a/client/src/components/composite/Admin/AdminBookingView/WrappedAdminBookingView.tsx b/client/src/components/composite/Admin/AdminBookingView/WrappedAdminBookingView.tsx index 389898025..2d01f75d6 100644 --- a/client/src/components/composite/Admin/AdminBookingView/WrappedAdminBookingView.tsx +++ b/client/src/components/composite/Admin/AdminBookingView/WrappedAdminBookingView.tsx @@ -7,6 +7,7 @@ import { Timestamp } from "firebase/firestore" import { useDeleteBookingMutation } from "@/services/Admin/AdminMutations" import { IAdminBookingDate } from "./AdminBookingDateDisplay/AdminBookingDate/AdminBookingDate" import Messages from "@/services/Utils/Messages" +import { compareStrings } from "@/services/Admin/AdminUtils" /** * Should be wrapped the `AdminBookingViewProvider` @@ -36,12 +37,22 @@ const WrappedAdminBookingView = () => { DateUtils.timestampMilliseconds(date.date) ) const bookingDate = DateUtils.formattedNzDate(bookingDateObject) + + /** + * Users should be displayed in ascending alphabetical order + * + * i.e _Alex_ comes before _John + */ + const sortedUsers = date.users.sort((a, b) => + compareStrings(a.first_name, b.first_name) + ) + return { dateString: bookingDate, dayName: bookingDateObject.toLocaleDateString("en-NZ", { weekday: "long" }), - users: date.users, + users: sortedUsers, handleUserDelete: (bookingId) => { if ( confirm( diff --git a/client/src/services/Admin/AdminUtils.test.ts b/client/src/services/Admin/AdminUtils.test.ts index ca81b8144..3599f1f72 100644 --- a/client/src/services/Admin/AdminUtils.test.ts +++ b/client/src/services/Admin/AdminUtils.test.ts @@ -1,4 +1,4 @@ -import { replaceUserInPage } from "./AdminUtils" +import { compareStrings, replaceUserInPage } from "./AdminUtils" global.structuredClone = (val) => JSON.parse(JSON.stringify(val)) @@ -34,3 +34,17 @@ describe("replaceUserInPage", () => { expect(originalUserDataPages).not.toEqual(updatedUserDataPages) }) }) + +describe("compareStrings", () => { + it("should return a negative value if a is alphabetically less than b", () => { + expect(compareStrings("abc", "abd")).toBeLessThan(0) + }) + + it("should return a positive value if a is alphabetically more than b", () => { + expect(compareStrings("abddd", "aaddd")).toBeGreaterThan(0) + }) + + it("should return 0 for equal strings", () => { + expect(compareStrings("abbb", "abbb")).toEqual(0) + }) +}) diff --git a/client/src/services/Admin/AdminUtils.ts b/client/src/services/Admin/AdminUtils.ts index 0bd034601..d81fd7746 100644 --- a/client/src/services/Admin/AdminUtils.ts +++ b/client/src/services/Admin/AdminUtils.ts @@ -28,3 +28,28 @@ export function replaceUserInPage( }) return updatedUserDataPages } + +/** + * Determines the order for strings when using the `sort` methods on an array + * + * @param a the first string to compare against + * @param b the second string to compare against + * + * @returns a **negative** number if `a` comes _before_ `b` alphabetically + * @returns a **positive** number if `a` comes _after_ `b` alphabetically + * @returns `0` if `a` and `b` are equal strings + */ +export function compareStrings(a: string, b: string) { + for (let i = 0; i < Math.min(a.length, b.length); ++i) { + const charCodeA = a.charCodeAt(i) + const charCodeB = b.charCodeAt(i) + + const difference = charCodeA - charCodeB + + if (difference !== 0) { + return difference + } + } + + return 0 +}