fix: add shift management (#41)
Release package / release (push) Successful in 10m13s

Co-authored-by: TakahashiNg <83152264+TakahashiNguyen@users.noreply.github.com>
Reviewed-on: #41
This commit was merged in pull request #41.
This commit is contained in:
2026-05-14 03:13:06 +00:00
parent dfcb1b09c0
commit 9ed4889310
18 changed files with 305 additions and 422 deletions
-86
View File
@@ -1,86 +0,0 @@
"use client";
import { SearchBar } from "@/components/molecules/search-bar";
import { ShopGrid } from "@/components/organisms/shop-grid";
import { useState } from "react";
export default function FeedPage() {
const [searchName, setSearchName] = useState("");
const [searchAddress, setSearchAddress] = useState("");
const hasFilters = searchName || searchAddress;
return (
<main className="bg-background min-h-[calc(100vh-var(--spacing-header-height))]">
<div className="mx-auto max-w-7xl px-4 py-8 md:px-6 lg:px-8">
{/* Page title */}
<div className="mb-8">
<h1 className="text-foreground text-2xl font-bold md:text-3xl">
Explore Shops
</h1>
<p className="mt-1 text-sm text-(--color-text-muted)">
Find and choose your favorite shop
</p>
</div>
{/* Shop grid */}
<div className="mb-10">
<ShopGrid searchName={searchName} searchAddress={searchAddress} />
{hasFilters && (
<div className="mt-4 flex justify-center">
<button
onClick={() => {
setSearchName("");
setSearchAddress("");
}}
className="cursor-pointer border-none bg-transparent text-sm text-(--color-primary) hover:underline"
>
Clear filters
</button>
</div>
)}
</div>
{/* Filter / Search bar — sticky bottom */}
<div className="sticky bottom-0 rounded-2xl border border-(--color-border) bg-(--color-bg-card) p-4 shadow-[0_-2px_16px_var(--color-shadow-sm)] md:p-5">
<div className="flex flex-col items-stretch gap-3 sm:flex-row sm:items-center">
<div className="flex shrink-0 items-center gap-2 text-sm font-semibold text-(--color-text-secondary)">
<i className="fa-solid fa-filter text-(--color-primary)"></i>
<span>Filter shops</span>
</div>
{/* Name search */}
<SearchBar
value={searchName}
onChange={setSearchName}
onClear={() => setSearchName("")}
placeholder="Search by shop name..."
className="min-w-0 flex-1"
/>
{/* Address search — different icon so not using SearchBar atom */}
<div className="relative min-w-0 flex-1">
<i className="fa-solid fa-location-dot pointer-events-none absolute top-1/2 left-3 -translate-y-1/2 text-xs text-(--color-text-muted)"></i>
<input
type="text"
value={searchAddress}
onChange={(e) => setSearchAddress(e.target.value)}
placeholder="Search by address..."
className="bg-background text-foreground focus:ring-opacity-20 w-full rounded-xl border border-(--color-border) py-2.5 pr-9 pl-9 text-sm transition-all duration-150 outline-none placeholder:text-(--color-text-muted) focus:border-(--color-primary) focus:ring-2 focus:ring-(--color-primary)"
/>
{searchAddress && (
<button
onClick={() => setSearchAddress("")}
aria-label="Clear address search"
className="absolute top-1/2 right-3 -translate-y-1/2 cursor-pointer border-none bg-transparent p-0 text-(--color-text-muted) transition-colors duration-150 hover:text-(--color-primary)"
>
<i className="fa-solid fa-xmark text-sm"></i>
</button>
)}
</div>
</div>
</div>
</div>
</main>
);
}
-9
View File
@@ -1,9 +0,0 @@
import { FeedLayout } from "@/components/templates/feed-layout";
export default function RootFeedLayout({
children,
}: {
children: React.ReactNode;
}) {
return <FeedLayout>{children}</FeedLayout>;
}
+6 -6
View File
@@ -7,7 +7,7 @@ import ShiftDetailModal from "@/components/organisms/shift-schedule/ShiftDetailM
import WeeklySchedule from "@/components/organisms/shift-schedule/WeeklySchedule";
import { useAuth } from "@/lib/auth-context";
import { useShift } from "@/lib/shift-context";
import type { ShiftSlot } from "@/lib/types";
import type { ShiftEntity } from "@/lib/types";
import Link from "next/link";
import { useState } from "react";
@@ -52,24 +52,24 @@ export default function StaffSchedulePage() {
getWeeklyBudget,
} = useShift();
const [selectedShift, setSelectedShift] = useState<ShiftSlot | null>(null);
const [selectedShift, setSelectedShift] = useState<ShiftEntity | null>(null);
const [detailOpen, setDetailOpen] = useState(false);
const [createOpen, setCreateOpen] = useState(false);
const [createDate, setCreateDate] = useState<string | undefined>();
const [createDate, setCreateDate] = useState<Date | undefined>();
const isManager = user?.role === "manager";
const handleShiftClick = (shift: ShiftSlot) => {
const handleShiftClick = (shift: ShiftEntity) => {
setSelectedShift(shift);
setDetailOpen(true);
};
const handleCreateShift = (date: string) => {
const handleCreateShift = (date: Date) => {
setCreateDate(date);
setCreateOpen(true);
};
const handleDateSelect = (date: string) => {
const handleDateSelect = (date: Date) => {
// In month view on desktop, clicking a date could open create modal for managers
if (isManager) {
setCreateDate(date);