Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions backend/docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ definitions:
type: integer
type: array
limit:
minimum: 0
type: integer
type: object
GenerateRequestInput:
Expand Down
28 changes: 28 additions & 0 deletions clients/web/src/components/rooms/FilterTag.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { X } from "lucide-react";
import { cn } from "@/lib/utils";

type FilterTagProps = {
label: string;
onRemove: () => void;
className?: string;
};

export function FilterTag({ label, onRemove, className }: FilterTagProps) {
return (
<div
className={cn(
className,
"inline-flex items-center gap-1 rounded-md border border-stroke-default pl-4 pr-3 py-1.5 text-sm text-text-default transition-colors",
)}
>
{label}
<button
type="button"
onClick={onRemove}
className="text-text-subtle hover:text-text-default"
>
<X className="h-4 w-4" />
</button>
</div>
);
}
60 changes: 60 additions & 0 deletions clients/web/src/components/rooms/OrderByDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { ChevronDown } from "lucide-react";
import { useState } from "react";
import { cn } from "@/lib/utils";

type OrderByDropdownProps = {
ascending: boolean;
setAscending: (ascending: boolean) => void;
};

export function OrderByDropdown({
ascending,
setAscending,
}: OrderByDropdownProps) {
const [open, setOpen] = useState(false);
const label = ascending ? "Ascending" : "Descending";

return (
<div
className="relative min-w-0 w-full max-w-31.5"
onBlur={(e) => {
if (!e.currentTarget.contains(e.relatedTarget)) setOpen(false);
}}
>
<button
type="button"
className={cn(
"flex w-full items-center justify-between gap-2 py-1 pl-2 pr-1 border border-stroke-subtle bg-bg-primary text-left",
open ? "rounded-t-md" : "rounded-md",
)}
onClick={() => setOpen((o) => !o)}
aria-expanded={open}
>
<span className="min-w-0 truncate text-md text-text-default">
{label}
</span>
<ChevronDown
className={cn(
"h-4 w-4 shrink-0 transition-transform",
open && "rotate-180",
)}
/>
</button>

{open && (
<div className="absolute left-0 top-full z-10 w-full rounded-b-md border border-t-0 border-stroke-subtle bg-bg-primary shadow-md">
<button
type="button"
className="block w-full pl-2 pr-1 py-1 text-left text-md text-text-default hover:bg-bg-selected"
onClick={() => {
setAscending(!ascending);
setOpen(false);
}}
>
{ascending ? "Descending" : "Ascending"}
</button>
</div>
)}
</div>
);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is good but def shadcn for future cases, you're the goat for cooking up from scratch though

21 changes: 20 additions & 1 deletion clients/web/src/components/rooms/RoomsList.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,41 @@
import { useMemo } from "react";
import type { RoomWithOptionalGuestBooking } from "@shared";
import { RoomCard } from "@/components/rooms/RoomCard";

type RoomsListProps = {
rooms: Array<RoomWithOptionalGuestBooking>;
onRoomSelect: (room: RoomWithOptionalGuestBooking) => void;
ascending: boolean;
selectedRoomNumber?: number | null;
};

function sortRoomsByRoomNumber(
rooms: Array<RoomWithOptionalGuestBooking>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ILoRoomWithOptionalGuestBooking

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a fundies reference? 😭

ascending: boolean,
): Array<RoomWithOptionalGuestBooking> {
return [...rooms].sort((a, b) => {
const an = a.room_number ?? 0;
const bn = b.room_number ?? 0;
return ascending ? an - bn : bn - an;
});
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we wanna do this sorting on the backend at the query level, we can merge this in for now but let's add that as a field to our request body as an optional sorting in a different pr


export function RoomsList({
rooms,
onRoomSelect,
ascending,
selectedRoomNumber = null,
}: RoomsListProps) {
const sortedRooms = useMemo(
() => sortRoomsByRoomNumber(rooms, ascending),
[rooms, ascending],
);

return (
<section className="flex-1 min-h-0 flex flex-col overflow-hidden py-4">
<nav className="flex-1 min-h-0">
<ul className="flex flex-col gap-4 h-full overflow-y-auto min-h-0 [&::-webkit-scrollbar]:hidden">
{rooms.map((room) => (
{sortedRooms.map((room) => (
<li key={room.room_number} className="min-w-0">
<RoomCard
room={room}
Expand Down
18 changes: 18 additions & 0 deletions clients/web/src/components/rooms/SortByContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { OrderByDropdown } from "./OrderByDropdown";

type SortByContainerProps = {
ascending: boolean;
setAscending: (ascending: boolean) => void;
};

export function SortByContainer({
ascending,
setAscending,
}: SortByContainerProps) {
return (
<span className="text-sm text-text-subtle flex items-center gap-1 pt-6">
Sort by:{" "}
<OrderByDropdown ascending={ascending} setAscending={setAscending} />
</span>
);
}
9 changes: 7 additions & 2 deletions clients/web/src/routes/_protected/rooms.index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useState } from "react";
import { usePostRoomsHook } from "@shared/api/generated/endpoints/rooms/rooms";
import { useQuery } from "@tanstack/react-query";
import type { RoomWithOptionalGuestBooking } from "@shared";
import { SortByContainer } from "@/components/rooms/SortByContainer";
import { PageShell } from "@/components/ui/PageShell";
import { RoomsHeader } from "@/components/rooms/RoomsHeader";
import { RoomsList } from "@/components/rooms/RoomsList";
Expand All @@ -16,10 +17,11 @@ function RoomsPage() {
const [selectedFloors, setSelectedFloors] = useState<Array<number>>([]);
const [selectedRoom, setSelectedRoom] =
useState<RoomWithOptionalGuestBooking | null>(null);
const [ascending, setAscending] = useState(true);

const postRooms = usePostRoomsHook();

const { data } = useQuery({
const { data: rooms } = useQuery({
queryKey: ["rooms", selectedFloors],
queryFn: () =>
postRooms({
Expand All @@ -44,8 +46,11 @@ function RoomsPage() {
/>
}
>
<SortByContainer ascending={ascending} setAscending={setAscending} />

<RoomsList
rooms={data?.items ?? []}
rooms={rooms?.items ?? []}
ascending={ascending}
onRoomSelect={setSelectedRoom}
selectedRoomNumber={selectedRoom?.room_number ?? null}
/>
Expand Down
1 change: 1 addition & 0 deletions clients/web/src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
--color-shadow: #e7e7e7;
--color-shadow-strong: #dcdcdc;
--color-bg-container: #f8f8f8;
--color-bg-disabled: #bababa;
--color-bg-primary: #ffffff;
--color-bg-secondary: #5d5d5d;
--color-bg-high-priority: #ffeded;
Expand Down
Loading