Sistem web pentru rezervarea de birouri și săli de ședință cu flux de aprobare administrativă. Stack: FastAPI + Vue.js 3 + SQLite + TypeScript Features implementate: - Autentificare JWT + Self-registration cu email verification - CRUD Spații, Utilizatori, Settings (Admin) - Calendar interactiv (FullCalendar) cu drag-and-drop - Creare rezervări cu validare (durată, program, overlap, max/zi) - Rezervări recurente (săptămânal) - Admin: aprobare/respingere/anulare cereri - Admin: creare directă rezervări (bypass approval) - Admin: editare orice rezervare - User: editare/anulare rezervări proprii - Notificări in-app (bell icon + dropdown) - Notificări email (async SMTP cu BackgroundTasks) - Jurnal acțiuni administrative (audit log) - Rapoarte avansate (utilizare, top users, approval rate) - Șabloane rezervări (booking templates) - Atașamente fișiere (upload/download) - Conflict warnings (verificare disponibilitate real-time) - Integrare Google Calendar (OAuth2) - Suport timezone (UTC storage + user preference) - 225+ teste backend Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
118 lines
3.4 KiB
TypeScript
118 lines
3.4 KiB
TypeScript
/**
|
|
* Utility functions for timezone-aware datetime formatting.
|
|
*/
|
|
|
|
/**
|
|
* Format a datetime string in the user's timezone.
|
|
*
|
|
* @param datetime - ISO datetime string from API (in UTC)
|
|
* @param timezone - IANA timezone string (e.g., "Europe/Bucharest")
|
|
* @param options - Intl.DateTimeFormat options
|
|
* @returns Formatted datetime string
|
|
*/
|
|
export const formatDateTime = (
|
|
datetime: string,
|
|
timezone: string = 'UTC',
|
|
options?: Intl.DateTimeFormatOptions
|
|
): string => {
|
|
const date = new Date(datetime)
|
|
|
|
const defaultOptions: Intl.DateTimeFormatOptions = {
|
|
timeZone: timezone,
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
...options
|
|
}
|
|
|
|
return new Intl.DateTimeFormat('ro-RO', defaultOptions).format(date)
|
|
}
|
|
|
|
/**
|
|
* Format date only (no time) in user's timezone.
|
|
*/
|
|
export const formatDate = (datetime: string, timezone: string = 'UTC'): string => {
|
|
return formatDateTime(datetime, timezone, {
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit',
|
|
hour: undefined,
|
|
minute: undefined
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Format time only in user's timezone.
|
|
*/
|
|
export const formatTime = (datetime: string, timezone: string = 'UTC'): string => {
|
|
const date = new Date(datetime)
|
|
return new Intl.DateTimeFormat('ro-RO', {
|
|
timeZone: timezone,
|
|
hour: '2-digit',
|
|
minute: '2-digit'
|
|
}).format(date)
|
|
}
|
|
|
|
/**
|
|
* Format datetime with timezone abbreviation.
|
|
*/
|
|
export const formatDateTimeWithTZ = (datetime: string, timezone: string = 'UTC'): string => {
|
|
const date = new Date(datetime)
|
|
|
|
const formatted = new Intl.DateTimeFormat('ro-RO', {
|
|
timeZone: timezone,
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
timeZoneName: 'short'
|
|
}).format(date)
|
|
|
|
return formatted
|
|
}
|
|
|
|
/**
|
|
* Get timezone abbreviation (e.g., "EET", "EEST").
|
|
*/
|
|
export const getTimezoneAbbr = (timezone: string = 'UTC'): string => {
|
|
const date = new Date()
|
|
const formatted = new Intl.DateTimeFormat('en-US', {
|
|
timeZone: timezone,
|
|
timeZoneName: 'short'
|
|
}).format(date)
|
|
|
|
// Extract timezone abbreviation from formatted string
|
|
const match = formatted.match(/,\s*(.+)/)
|
|
return match ? match[1] : timezone.split('/').pop() || 'UTC'
|
|
}
|
|
|
|
/**
|
|
* Convert local datetime-local input to ISO string (for API).
|
|
* The input from datetime-local is in user's local time, so we just add seconds and Z.
|
|
*/
|
|
export const localDateTimeToISO = (localDateTime: string): string => {
|
|
// datetime-local format: "YYYY-MM-DDTHH:mm"
|
|
// We need to send it as is to the API (API will handle timezone conversion)
|
|
return localDateTime + ':00'
|
|
}
|
|
|
|
/**
|
|
* Convert ISO datetime to datetime-local format for input field.
|
|
*/
|
|
export const isoToLocalDateTime = (isoDateTime: string, timezone: string = 'UTC'): string => {
|
|
const date = new Date(isoDateTime)
|
|
|
|
// Get the date components in the user's timezone
|
|
const year = date.toLocaleString('en-US', { timeZone: timezone, year: 'numeric' })
|
|
const month = date.toLocaleString('en-US', { timeZone: timezone, month: '2-digit' })
|
|
const day = date.toLocaleString('en-US', { timeZone: timezone, day: '2-digit' })
|
|
const hour = date.toLocaleString('en-US', { timeZone: timezone, hour: '2-digit', hour12: false })
|
|
const minute = date.toLocaleString('en-US', { timeZone: timezone, minute: '2-digit' })
|
|
|
|
// Format as YYYY-MM-DDTHH:mm for datetime-local input
|
|
return `${year}-${month}-${day}T${hour.padStart(2, '0')}:${minute}`
|
|
}
|