bugfix: appointment hours now use the client timezone on UTC servers.

Logical API errors throw stable codes so users see translated messages instead of a generic bad request.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-19 01:43:50 +03:30
parent d6958b2e48
commit 80167c622c
38 changed files with 833 additions and 392 deletions

View File

@@ -1,4 +1,5 @@
import { apiClient } from './client';
import { getClientTimeZone } from '@/lib/i18n/clientTimeZone';
export type WorkingHoursPayload = {
autoRepeatWeekly: boolean;
@@ -42,7 +43,10 @@ export const accountApi = {
upsertMyWorkingHours: async (
payload: WorkingHoursPayload,
): Promise<{ success: boolean; message: string }> => {
const response = await apiClient.put('/auth/profile/working-hours', payload);
const response = await apiClient.put('/auth/profile/working-hours', {
...payload,
timeZone: getClientTimeZone(),
});
return response.data;
},
};

View File

@@ -1,5 +1,6 @@
import { apiClient } from './client';
import type { AppointmentColumnProvider, AppointmentRecord } from '@/types/appointment';
import { getClientTimeZone } from '@/lib/i18n/clientTimeZone';
import { toDateInputValue } from '@/components/appointments/appointmentTime';
export interface CreateAppointmentBody {
@@ -27,7 +28,10 @@ export const appointmentsApi = {
},
create: async (body: CreateAppointmentBody): Promise<{ success: boolean; data: AppointmentRecord }> => {
const response = await apiClient.post('/appointments', body);
const response = await apiClient.post('/appointments', {
...body,
timeZone: getClientTimeZone(),
});
return response.data;
},
@@ -35,7 +39,10 @@ export const appointmentsApi = {
id: string,
body: UpdateAppointmentBody,
): Promise<{ success: boolean; data: AppointmentRecord }> => {
const response = await apiClient.patch(`/appointments/${id}`, body);
const response = await apiClient.patch(`/appointments/${id}`, {
...body,
timeZone: getClientTimeZone(),
});
return response.data;
},

View File

@@ -1,4 +1,5 @@
import { apiClient } from './client';
import { getClientTimeZone } from '@/lib/i18n/clientTimeZone';
export interface StaffMemberDto {
id: string;
@@ -142,7 +143,10 @@ export const staffApi = {
blocks: { dayOfWeek: number; startMinute: number; endMinute: number; sortOrder?: number }[];
},
): Promise<{ success: boolean; message: string }> => {
const response = await apiClient.put(`/staff/members/${membershipId}/working-hours`, body);
const response = await apiClient.put(`/staff/members/${membershipId}/working-hours`, {
...body,
timeZone: getClientTimeZone(),
});
return response.data;
},
};

View File

@@ -0,0 +1,8 @@
/** Browser IANA zone (e.g. Asia/Tehran). Used so the UTC server can interpret wall-clock hours. */
export function getClientTimeZone(): string {
try {
return Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC';
} catch {
return 'UTC';
}
}