diff --git a/Makefile b/Makefile index 2b0f75c..952131c 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: install-backend install-frontend install setup-hooks backend frontend db db-stop db-ready db-seed dev test test-backend test-frontend test-e2e typecheck generate-types generate-types-standalone check-types-fresh check-constants lint-backend format-backend fix-backend security-backend lint-frontend fix-frontend +.PHONY: install-backend install-frontend install setup-hooks backend frontend db db-stop db-ready db-seed dev test test-backend test-frontend test-e2e typecheck generate-types generate-types-standalone check-types-fresh check-constants lint-backend format-backend fix-backend security-backend lint-frontend fix-frontend format-frontend -include .env export @@ -111,3 +111,6 @@ lint-frontend: fix-frontend: cd frontend && npm run lint:fix + +format-frontend: + cd frontend && npm run format diff --git a/frontend/.prettierignore b/frontend/.prettierignore new file mode 100644 index 0000000..7898f26 --- /dev/null +++ b/frontend/.prettierignore @@ -0,0 +1,4 @@ +.next/ +node_modules/ +app/generated/ + diff --git a/frontend/.prettierrc.json b/frontend/.prettierrc.json new file mode 100644 index 0000000..1a88ab1 --- /dev/null +++ b/frontend/.prettierrc.json @@ -0,0 +1,7 @@ +{ + "semi": true, + "singleQuote": false, + "tabWidth": 2, + "trailingComma": "es5", + "printWidth": 100 +} diff --git a/frontend/app/admin/appointments/page.tsx b/frontend/app/admin/appointments/page.tsx index 616b46b..4af5964 100644 --- a/frontend/app/admin/appointments/page.tsx +++ b/frontend/app/admin/appointments/page.tsx @@ -189,7 +189,7 @@ export default function AdminAppointmentsPage() { const handleCancel = async (appointmentId: number) => { setCancellingId(appointmentId); setError(null); - + try { await api.post(`/api/admin/appointments/${appointmentId}/cancel`, {}); await fetchAppointments(); @@ -225,13 +225,9 @@ export default function AdminAppointmentsPage() {

All Appointments

-

- View and manage all user appointments -

+

View and manage all user appointments

- {error && ( -
{error}
- )} + {error &&
{error}
} {/* Status Filter */}
@@ -269,26 +265,20 @@ export default function AdminAppointmentsPage() { >
-
- {formatDateTime(apt.slot_start)} -
-
- {apt.user_email} -
- {apt.note && ( -
- "{apt.note}" -
- )} - +
{formatDateTime(apt.slot_start)}
+
{apt.user_email}
+ {apt.note &&
"{apt.note}"
} + {status.text}
- + {apt.status === "booked" && (
{confirmCancelId === apt.id ? ( @@ -327,4 +317,3 @@ export default function AdminAppointmentsPage() { ); } - diff --git a/frontend/app/admin/availability/page.tsx b/frontend/app/admin/availability/page.tsx index ba3c889..255b657 100644 --- a/frontend/app/admin/availability/page.tsx +++ b/frontend/app/admin/availability/page.tsx @@ -8,7 +8,13 @@ import { Header } from "../../components/Header"; import { useRequireAuth } from "../../hooks/useRequireAuth"; import { components } from "../../generated/api"; import constants from "../../../../shared/constants.json"; -import { formatDate, formatDisplayDate, getDateRange, formatTimeString, isWeekend } from "../../utils/date"; +import { + formatDate, + formatDisplayDate, + getDateRange, + formatTimeString, + isWeekend, +} from "../../utils/date"; const { slotDurationMinutes, maxAdvanceDays, minAdvanceDays } = constants.booking; @@ -57,14 +63,14 @@ export default function AdminAvailabilityPage() { const fetchAvailability = useCallback(async () => { const dateRange = getDateRange(minAdvanceDays, maxAdvanceDays); if (!dateRange.length) return; - + try { const fromDate = formatDate(dateRange[0]); const toDate = formatDate(dateRange[dateRange.length - 1]); const data = await api.get( `/api/admin/availability?from=${fromDate}&to=${toDate}` ); - + const map = new Map(); for (const day of data.days) { map.set(day.date, day.slots); @@ -118,21 +124,21 @@ export default function AdminAvailabilityPage() { const saveAvailability = async () => { if (!selectedDate) return; - + setIsSaving(true); setError(null); - + try { const slots = editSlots.map((s) => ({ start_time: s.start_time + ":00", end_time: s.end_time + ":00", })); - + await api.put("/api/admin/availability", { date: formatDate(selectedDate), slots, }); - + await fetchAvailability(); closeModal(); } catch (err) { @@ -144,16 +150,16 @@ export default function AdminAvailabilityPage() { const clearAvailability = async () => { if (!selectedDate) return; - + setIsSaving(true); setError(null); - + try { await api.put("/api/admin/availability", { date: formatDate(selectedDate), slots: [], }); - + await fetchAvailability(); closeModal(); } catch (err) { @@ -186,16 +192,16 @@ export default function AdminAvailabilityPage() { const executeCopy = async () => { if (!copySource || copyTargets.size === 0) return; - + setIsCopying(true); setError(null); - + try { await api.post("/api/admin/availability/copy", { source_date: copySource, target_dates: Array.from(copyTargets), }); - + await fetchAvailability(); cancelCopyMode(); } catch (err) { @@ -236,10 +242,12 @@ export default function AdminAvailabilityPage() {
{copySource && (
- - Select days to copy to, then click Copy - -
- {error && !selectedDate && ( -
{error}
- )} + {error && !selectedDate &&
{error}
}
{dates.map((date) => { @@ -318,9 +324,7 @@ export default function AdminAvailabilityPage() { {selectedDate && (
e.stopPropagation()}> -

- Edit Availability - {formatDisplayDate(selectedDate)} -

+

Edit Availability - {formatDisplayDate(selectedDate)}

{error &&
{error}
} @@ -333,7 +337,9 @@ export default function AdminAvailabilityPage() { style={styles.timeSelect} > {TIME_OPTIONS.map((t) => ( - + ))} @@ -343,7 +349,9 @@ export default function AdminAvailabilityPage() { style={styles.timeSelect} > {TIME_OPTIONS.map((t) => ( - + ))}
- +
@@ -206,43 +204,48 @@ export default function AdminInvitesPage() { {error && ( - + )} - {!error && data?.records.map((record) => ( - - - - - - - + + + - - ))} + {record.status} + + + + + + + ))} {!error && (!data || data.records.length === 0) && ( - + )}
{error} + {error} +
{record.identifier}{record.godfather_email} - - {record.status} - - - {record.used_by_email || "-"} - {formatDate(record.created_at)} - {record.status === READY && ( -
{record.identifier}{record.godfather_email} + - Revoke - - )} -
{record.used_by_email || "-"}{formatDate(record.created_at)} + {record.status === READY && ( + + )} +
No invites yet + No invites yet +
- + {data && data.total_pages > 1 && (