mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-08-26 19:12:50 +00:00
feat: integrate AmharicDatePicker component across multiple pages and update translations
This commit is contained in:
@@ -1,6 +1,13 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { ActionIcon, Button, Group, Popover, TextInput } from '@mantine/core';
|
import {
|
||||||
|
ActionIcon,
|
||||||
|
Button,
|
||||||
|
Group,
|
||||||
|
MantineSize,
|
||||||
|
Popover,
|
||||||
|
TextInput,
|
||||||
|
} from '@mantine/core';
|
||||||
import { useDisclosure } from '@mantine/hooks';
|
import { useDisclosure } from '@mantine/hooks';
|
||||||
import { DayPicker as EthiopicDayPicker } from '@daypicker/ethiopic';
|
import { DayPicker as EthiopicDayPicker } from '@daypicker/ethiopic';
|
||||||
import { DayPicker as GregorianDayPicker } from '@daypicker/react';
|
import { DayPicker as GregorianDayPicker } from '@daypicker/react';
|
||||||
@@ -52,23 +59,48 @@ const ETH_FORMATTERS = {
|
|||||||
formatMonthDropdown: (month: Date) => ethMonthName(month),
|
formatMonthDropdown: (month: Date) => ethMonthName(month),
|
||||||
};
|
};
|
||||||
|
|
||||||
export function toEthiopicDateLabel(date: Date): string {
|
// Local-date parse/format for the "YYYY-MM-DD" wire format (matches native
|
||||||
|
// <input type="date"> semantics). Deliberately NOT `new Date(iso)` (parses as
|
||||||
|
// UTC midnight, off-by-one in negative-offset zones) and NOT
|
||||||
|
// `.toISOString()` (shifts by the local offset when formatting) — same class
|
||||||
|
// of bug the UTC-noon workaround above already had to fix once in this file.
|
||||||
|
function parseISO(value?: string | null): Date | null {
|
||||||
|
if (!value) return null;
|
||||||
|
const [y, m, d] = value.split('-').map(Number);
|
||||||
|
return y && m && d ? new Date(y, m - 1, d) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatISO(date: Date): string {
|
||||||
|
const y = date.getFullYear();
|
||||||
|
const m = String(date.getMonth() + 1).padStart(2, '0');
|
||||||
|
const d = String(date.getDate()).padStart(2, '0');
|
||||||
|
return `${y}-${m}-${d}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toEthiopicDateLabel(date: Date | string): string {
|
||||||
|
const d = typeof date === 'string' ? parseISO(date) : date;
|
||||||
|
if (!d) return '';
|
||||||
try {
|
try {
|
||||||
const eth = toEthDateTime(date);
|
const eth = toEthDateTime(d);
|
||||||
return `EC ${eth.year}-${String(eth.month).padStart(2, '0')}-${String(eth.date).padStart(2, '0')}`;
|
return `EC ${eth.year}-${String(eth.month).padStart(2, '0')}-${String(eth.date).padStart(2, '0')}`;
|
||||||
} catch {
|
} catch {
|
||||||
return date.toLocaleDateString('en-US');
|
return d.toLocaleDateString('en-US');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const YEAR_DROPDOWN_END = new Date(new Date().getFullYear() + 50, 11, 31);
|
const YEAR_DROPDOWN_END = new Date(new Date().getFullYear() + 50, 11, 31);
|
||||||
|
|
||||||
export interface AmharicDatePickerProps {
|
export interface AmharicDatePickerProps {
|
||||||
label?: string;
|
label?: React.ReactNode;
|
||||||
value?: Date | null;
|
value?: string | null;
|
||||||
onChange?: (date: Date | null) => void;
|
onChange?: (value: string) => void;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
|
error?: React.ReactNode;
|
||||||
|
disabled?: boolean;
|
||||||
|
size?: MantineSize;
|
||||||
|
name?: string;
|
||||||
|
onBlur?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AmharicDatePicker({
|
export function AmharicDatePicker({
|
||||||
@@ -77,21 +109,28 @@ export function AmharicDatePicker({
|
|||||||
onChange,
|
onChange,
|
||||||
required,
|
required,
|
||||||
placeholder,
|
placeholder,
|
||||||
|
error,
|
||||||
|
disabled,
|
||||||
|
size,
|
||||||
|
name,
|
||||||
|
onBlur,
|
||||||
}: AmharicDatePickerProps) {
|
}: AmharicDatePickerProps) {
|
||||||
const { i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const [calendarType, setCalendarType] = useState<'EN' | 'AMH'>(() =>
|
const [calendarType, setCalendarType] = useState<'EN' | 'AMH'>(() =>
|
||||||
i18n.language?.startsWith('am') ? 'AMH' : 'EN',
|
i18n.language?.startsWith('am') ? 'AMH' : 'EN',
|
||||||
);
|
);
|
||||||
const [opened, { close, toggle }] = useDisclosure(false);
|
const [opened, { close, toggle }] = useDisclosure(false);
|
||||||
|
|
||||||
const displayValue = value
|
const selected = parseISO(value);
|
||||||
|
|
||||||
|
const displayValue = selected
|
||||||
? calendarType === 'EN'
|
? calendarType === 'EN'
|
||||||
? value.toLocaleDateString('en-US', {
|
? selected.toLocaleDateString('en-US', {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
month: 'long',
|
month: 'long',
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
})
|
})
|
||||||
: toAmharicDisplay(value)
|
: toAmharicDisplay(selected)
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -109,24 +148,32 @@ export function AmharicDatePicker({
|
|||||||
required={required}
|
required={required}
|
||||||
value={displayValue}
|
value={displayValue}
|
||||||
readOnly
|
readOnly
|
||||||
|
disabled={disabled}
|
||||||
|
size={size}
|
||||||
|
name={name}
|
||||||
|
error={error}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
onClick={toggle}
|
onClick={() => !disabled && toggle()}
|
||||||
|
onBlur={onBlur}
|
||||||
leftSection={
|
leftSection={
|
||||||
<Button
|
<Button
|
||||||
|
type="button"
|
||||||
variant="light"
|
variant="light"
|
||||||
size="compact-xs"
|
size="compact-xs"
|
||||||
|
tabIndex={0}
|
||||||
|
disabled={disabled}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setCalendarType((prev) => (prev === 'EN' ? 'AMH' : 'EN'));
|
setCalendarType((prev) => (prev === 'EN' ? 'AMH' : 'EN'));
|
||||||
}}
|
}}
|
||||||
aria-label="Switch calendar type"
|
aria-label={t('common.switchCalendar')}
|
||||||
>
|
>
|
||||||
{calendarType}
|
{calendarType}
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
leftSectionWidth="calc(4.375rem * var(--mantine-scale))"
|
leftSectionWidth="calc(4.375rem * var(--mantine-scale))"
|
||||||
rightSection={
|
rightSection={
|
||||||
<ActionIcon size="md" variant="transparent" onClick={toggle}>
|
<ActionIcon size="md" variant="transparent" disabled={disabled} onClick={() => toggle()}>
|
||||||
<IconCalendarEvent size={20} />
|
<IconCalendarEvent size={20} />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
}
|
}
|
||||||
@@ -138,14 +185,14 @@ export function AmharicDatePicker({
|
|||||||
<EthiopicDayPicker
|
<EthiopicDayPicker
|
||||||
className="amharic-daypicker"
|
className="amharic-daypicker"
|
||||||
mode="single"
|
mode="single"
|
||||||
selected={value ?? undefined}
|
selected={selected ?? undefined}
|
||||||
defaultMonth={value ?? undefined}
|
defaultMonth={selected ?? undefined}
|
||||||
endMonth={YEAR_DROPDOWN_END}
|
endMonth={YEAR_DROPDOWN_END}
|
||||||
numerals="latn"
|
numerals="latn"
|
||||||
captionLayout="dropdown"
|
captionLayout="dropdown"
|
||||||
formatters={ETH_FORMATTERS}
|
formatters={ETH_FORMATTERS}
|
||||||
onSelect={(date: Date | undefined) => {
|
onSelect={(date: Date | undefined) => {
|
||||||
onChange?.(date ?? null);
|
onChange?.(date ? formatISO(date) : '');
|
||||||
close();
|
close();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -153,12 +200,12 @@ export function AmharicDatePicker({
|
|||||||
<GregorianDayPicker
|
<GregorianDayPicker
|
||||||
className="amharic-daypicker"
|
className="amharic-daypicker"
|
||||||
mode="single"
|
mode="single"
|
||||||
selected={value ?? undefined}
|
selected={selected ?? undefined}
|
||||||
defaultMonth={value ?? undefined}
|
defaultMonth={selected ?? undefined}
|
||||||
endMonth={YEAR_DROPDOWN_END}
|
endMonth={YEAR_DROPDOWN_END}
|
||||||
captionLayout="dropdown"
|
captionLayout="dropdown"
|
||||||
onSelect={(date: Date | undefined) => {
|
onSelect={(date: Date | undefined) => {
|
||||||
onChange?.(date ?? null);
|
onChange?.(date ? formatISO(date) : '');
|
||||||
close();
|
close();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -169,7 +216,7 @@ export function AmharicDatePicker({
|
|||||||
variant="subtle"
|
variant="subtle"
|
||||||
size="xs"
|
size="xs"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onChange?.(null);
|
onChange?.('');
|
||||||
close();
|
close();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -179,7 +226,7 @@ export function AmharicDatePicker({
|
|||||||
variant="light"
|
variant="light"
|
||||||
size="xs"
|
size="xs"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onChange?.(new Date());
|
onChange?.(formatISO(new Date()));
|
||||||
close();
|
close();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
|
import { AmharicDatePicker } from '../../../components/AmharicDatePicker';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
Badge,
|
Badge,
|
||||||
@@ -202,9 +203,9 @@ function UploadModal({
|
|||||||
<TextInput label="Issuing Institution" placeholder="e.g. Bahirdar Maritime School" required value={issuer} onChange={(e) => setIssuer(e.currentTarget.value)} size="sm" />
|
<TextInput label="Issuing Institution" placeholder="e.g. Bahirdar Maritime School" required value={issuer} onChange={(e) => setIssuer(e.currentTarget.value)} size="sm" />
|
||||||
<TextInput label="Certificate Number" placeholder="e.g. PST-2024-001" required value={certNumber} onChange={(e) => setCertNumber(e.currentTarget.value)} size="sm" />
|
<TextInput label="Certificate Number" placeholder="e.g. PST-2024-001" required value={certNumber} onChange={(e) => setCertNumber(e.currentTarget.value)} size="sm" />
|
||||||
<SimpleGrid cols={2} spacing="sm">
|
<SimpleGrid cols={2} spacing="sm">
|
||||||
<TextInput label="Issue Date" type="date" required value={issueDate} onChange={(e) => setIssueDate(e.currentTarget.value)} size="sm" />
|
<AmharicDatePicker label="Issue Date" required value={issueDate} onChange={setIssueDate} size="sm" />
|
||||||
{item.refreshYears > 0 && (
|
{item.refreshYears > 0 && (
|
||||||
<TextInput label={`Expiry Date (${item.refreshYears}-yr refresh)`} type="date" value={expiryDate} onChange={(e) => setExpiryDate(e.currentTarget.value)} size="sm" />
|
<AmharicDatePicker label={`Expiry Date (${item.refreshYears}-yr refresh)`} value={expiryDate} onChange={setExpiryDate} size="sm" />
|
||||||
)}
|
)}
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { AmharicDatePicker } from '../../../components/AmharicDatePicker';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
Badge,
|
Badge,
|
||||||
@@ -999,11 +1000,10 @@ export function CoCApplicationPage() {
|
|||||||
size="sm"
|
size="sm"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<AmharicDatePicker
|
||||||
label="Payment Date"
|
label="Payment Date"
|
||||||
type="date"
|
|
||||||
value={paymentDate}
|
value={paymentDate}
|
||||||
onChange={(e) => setPaymentDate(e.currentTarget.value)}
|
onChange={setPaymentDate}
|
||||||
size="sm"
|
size="sm"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { CountrySelect, getCountryName } from '@ema-platform/ui';
|
import { CountrySelect, getCountryName } from '@ema-platform/ui';
|
||||||
|
import { AmharicDatePicker } from '../../../components/AmharicDatePicker';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
Badge,
|
Badge,
|
||||||
@@ -133,8 +134,8 @@ function ApplicationWizard({ onDone }: { onDone: () => void }) {
|
|||||||
<CountrySelect label="Issuing Country" value={country} onChange={setCountry} required />
|
<CountrySelect label="Issuing Country" value={country} onChange={setCountry} required />
|
||||||
<TextInput label="Issuing Authority / Administration" placeholder="e.g. Maritime Industry Authority (MARINA)" value={issuer} onChange={(e) => setIssuer(e.currentTarget.value)} required />
|
<TextInput label="Issuing Authority / Administration" placeholder="e.g. Maritime Industry Authority (MARINA)" value={issuer} onChange={(e) => setIssuer(e.currentTarget.value)} required />
|
||||||
<TextInput label="Certificate Type" placeholder="e.g. Officer in Charge of a Navigational Watch" value={cocType} onChange={(e) => setCocType(e.currentTarget.value)} required />
|
<TextInput label="Certificate Type" placeholder="e.g. Officer in Charge of a Navigational Watch" value={cocType} onChange={(e) => setCocType(e.currentTarget.value)} required />
|
||||||
<TextInput label="Issue Date" type="date" value={issueDate} onChange={(e) => setIssueDate(e.currentTarget.value)} required />
|
<AmharicDatePicker label="Issue Date" value={issueDate} onChange={setIssueDate} required />
|
||||||
<TextInput label="Expiry Date" type="date" value={expiryDate} onChange={(e) => setExpiryDate(e.currentTarget.value)} required />
|
<AmharicDatePicker label="Expiry Date" value={expiryDate} onChange={setExpiryDate} required />
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</Paper>
|
</Paper>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useApiMutation } from '@ema-platform/api';
|
import { useApiMutation } from '@ema-platform/api';
|
||||||
|
import { AmharicDatePicker } from '../../../components/AmharicDatePicker';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
Badge,
|
Badge,
|
||||||
@@ -447,7 +448,7 @@ export function JointInvestmentLicenseApplicationPage() {
|
|||||||
<SectionHead title="Business License and Registration Information" />
|
<SectionHead title="Business License and Registration Information" />
|
||||||
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md">
|
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md">
|
||||||
<TextInput label="Budget Year" required value={budgetYear} onChange={(e) => setBudgetYear(e.currentTarget.value)} />
|
<TextInput label="Budget Year" required value={budgetYear} onChange={(e) => setBudgetYear(e.currentTarget.value)} />
|
||||||
<TextInput label="License Validity Date" required placeholder="YYYY-MM-DD" value={licenseValidityDate} onChange={(e) => setLicenseValidityDate(e.currentTarget.value)} />
|
<AmharicDatePicker label="License Validity Date" required value={licenseValidityDate} onChange={setLicenseValidityDate} />
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
|
import { AmharicDatePicker } from '../../../components/AmharicDatePicker';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
Badge,
|
Badge,
|
||||||
@@ -224,18 +225,16 @@ export function MedicalCertificatePage() {
|
|||||||
size="sm"
|
size="sm"
|
||||||
/>
|
/>
|
||||||
<SimpleGrid cols={2} spacing="sm">
|
<SimpleGrid cols={2} spacing="sm">
|
||||||
<TextInput
|
<AmharicDatePicker
|
||||||
label="Issue Date"
|
label="Issue Date"
|
||||||
type="date"
|
|
||||||
value={issuedDate}
|
value={issuedDate}
|
||||||
onChange={(e) => setIssuedDate(e.currentTarget.value)}
|
onChange={setIssuedDate}
|
||||||
size="sm"
|
size="sm"
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<AmharicDatePicker
|
||||||
label="Expiry Date"
|
label="Expiry Date"
|
||||||
type="date"
|
|
||||||
value={expiryDate}
|
value={expiryDate}
|
||||||
onChange={(e) => setExpiryDate(e.currentTarget.value)}
|
onChange={setExpiryDate}
|
||||||
size="sm"
|
size="sm"
|
||||||
/>
|
/>
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useApiMutation } from '@ema-platform/api';
|
import { useApiMutation } from '@ema-platform/api';
|
||||||
|
import { AmharicDatePicker } from '../../../components/AmharicDatePicker';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
Badge,
|
Badge,
|
||||||
@@ -572,8 +573,8 @@ export function MtoLicenseApplicationPage() {
|
|||||||
<DocCard slot={{ key: 'customsBondDoc', label: 'Customs Bond Document', description: 'Customs bond documentation', required: true, icon: IconShieldCheck }} file={customsBondDoc} onFile={setCustomsBondDoc} />
|
<DocCard slot={{ key: 'customsBondDoc', label: 'Customs Bond Document', description: 'Customs bond documentation', required: true, icon: IconShieldCheck }} file={customsBondDoc} onFile={setCustomsBondDoc} />
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md" mt="xs">
|
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md" mt="xs">
|
||||||
<TextInput label="Insurance Validity Date" required placeholder="YYYY-MM-DD" value={insuranceValidityDate} onChange={(e) => setInsuranceValidityDate(e.currentTarget.value)} />
|
<AmharicDatePicker label="Insurance Validity Date" required value={insuranceValidityDate} onChange={setInsuranceValidityDate} />
|
||||||
<TextInput label="Bond Validity Date" required placeholder="YYYY-MM-DD" value={bondValidityDate} onChange={(e) => setBondValidityDate(e.currentTarget.value)} />
|
<AmharicDatePicker label="Bond Validity Date" required value={bondValidityDate} onChange={setBondValidityDate} />
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Loader, Select, SimpleGrid, TextInput } from '@mantine/core';
|
import { Loader, Select, SimpleGrid, TextInput } from '@mantine/core';
|
||||||
import type { FieldErrors, UseFormRegister, UseFormSetValue, UseFormWatch, UseFormTrigger } from 'react-hook-form';
|
import type { FieldErrors, UseFormRegister, UseFormSetValue, UseFormWatch, UseFormTrigger } from 'react-hook-form';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
import { AmharicDatePicker } from '../../../components/AmharicDatePicker';
|
||||||
|
|
||||||
export const profileSchema = z.object({
|
export const profileSchema = z.object({
|
||||||
professionId: z.string().min(1, 'Select your profession'),
|
professionId: z.string().min(1, 'Select your profession'),
|
||||||
@@ -86,11 +87,13 @@ export function ProfileFormContent({
|
|||||||
onBlur={() => trigger('gender')}
|
onBlur={() => trigger('gender')}
|
||||||
name="gender"
|
name="gender"
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<AmharicDatePicker
|
||||||
label="Date of Birth"
|
label="Date of Birth"
|
||||||
type="date"
|
|
||||||
required
|
required
|
||||||
{...register('dob')}
|
value={watch('dob')}
|
||||||
|
onChange={(val) => setValue('dob', val, { shouldValidate: true })}
|
||||||
|
onBlur={() => trigger('dob')}
|
||||||
|
name="dob"
|
||||||
error={errors.dob?.message}
|
error={errors.dob?.message}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import { AmharicDatePicker } from '../../../components/AmharicDatePicker';
|
||||||
import {
|
import {
|
||||||
ActionIcon,
|
ActionIcon,
|
||||||
Alert,
|
Alert,
|
||||||
@@ -462,6 +463,9 @@ function HistoryTab({ entries }: { entries: HistoryEntry[] }) {
|
|||||||
// Add Record Modal (generic)
|
// Add Record Modal (generic)
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
function AddTrainingModal({ opened, onClose }: { opened: boolean; onClose: () => void }) {
|
function AddTrainingModal({ opened, onClose }: { opened: boolean; onClose: () => void }) {
|
||||||
|
const [issueDate, setIssueDate] = useState('');
|
||||||
|
const [expiryDate, setExpiryDate] = useState('');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal opened={opened} onClose={onClose} title="Add Training Record" size="lg">
|
<Modal opened={opened} onClose={onClose} title="Add Training Record" size="lg">
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
@@ -471,8 +475,8 @@ function AddTrainingModal({ opened, onClose }: { opened: boolean; onClose: () =>
|
|||||||
<TextInput label="Certificate No." placeholder="CERT-0000" />
|
<TextInput label="Certificate No." placeholder="CERT-0000" />
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
<SimpleGrid cols={2} spacing="sm">
|
<SimpleGrid cols={2} spacing="sm">
|
||||||
<TextInput label="Issue Date" type="date" />
|
<AmharicDatePicker label="Issue Date" value={issueDate} onChange={setIssueDate} />
|
||||||
<TextInput label="Expiry Date" type="date" />
|
<AmharicDatePicker label="Expiry Date" value={expiryDate} onChange={setExpiryDate} />
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
<Select label="Status" data={['Approved', 'Pending', 'Expired']} defaultValue="Pending" />
|
<Select label="Status" data={['Approved', 'Pending', 'Expired']} defaultValue="Pending" />
|
||||||
<Group justify="flex-end" mt="sm">
|
<Group justify="flex-end" mt="sm">
|
||||||
@@ -485,14 +489,17 @@ function AddTrainingModal({ opened, onClose }: { opened: boolean; onClose: () =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
function AddMedicalModal({ opened, onClose }: { opened: boolean; onClose: () => void }) {
|
function AddMedicalModal({ opened, onClose }: { opened: boolean; onClose: () => void }) {
|
||||||
|
const [issueDate, setIssueDate] = useState('');
|
||||||
|
const [expiryDate, setExpiryDate] = useState('');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal opened={opened} onClose={onClose} title="Add Medical Record" size="lg">
|
<Modal opened={opened} onClose={onClose} title="Add Medical Record" size="lg">
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<TextInput label="Exam Type" placeholder="e.g. STCW Medical Certificate" required />
|
<TextInput label="Exam Type" placeholder="e.g. STCW Medical Certificate" required />
|
||||||
<TextInput label="Issued By" placeholder="Issuing authority" />
|
<TextInput label="Issued By" placeholder="Issuing authority" />
|
||||||
<SimpleGrid cols={2} spacing="sm">
|
<SimpleGrid cols={2} spacing="sm">
|
||||||
<TextInput label="Issue Date" type="date" />
|
<AmharicDatePicker label="Issue Date" value={issueDate} onChange={setIssueDate} />
|
||||||
<TextInput label="Expiry Date" type="date" />
|
<AmharicDatePicker label="Expiry Date" value={expiryDate} onChange={setExpiryDate} />
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
<Select label="Result" data={['Fit', 'Unfit', 'Conditional']} defaultValue="Fit" />
|
<Select label="Result" data={['Fit', 'Unfit', 'Conditional']} defaultValue="Fit" />
|
||||||
<Textarea label="Remarks" placeholder="Any notes" autosize minRows={2} />
|
<Textarea label="Remarks" placeholder="Any notes" autosize minRows={2} />
|
||||||
@@ -507,6 +514,8 @@ function AddMedicalModal({ opened, onClose }: { opened: boolean; onClose: () =>
|
|||||||
|
|
||||||
function AddSeaServiceModal({ opened, onClose }: { opened: boolean; onClose: () => void }) {
|
function AddSeaServiceModal({ opened, onClose }: { opened: boolean; onClose: () => void }) {
|
||||||
const [flag, setFlag] = useState<string | null>(null);
|
const [flag, setFlag] = useState<string | null>(null);
|
||||||
|
const [fromDate, setFromDate] = useState('');
|
||||||
|
const [toDate, setToDate] = useState('');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal opened={opened} onClose={onClose} title="Add Sea Service Record" size="lg">
|
<Modal opened={opened} onClose={onClose} title="Add Sea Service Record" size="lg">
|
||||||
@@ -520,8 +529,8 @@ function AddSeaServiceModal({ opened, onClose }: { opened: boolean; onClose: ()
|
|||||||
<CountrySelect label="Flag" value={flag} onChange={setFlag} />
|
<CountrySelect label="Flag" value={flag} onChange={setFlag} />
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
<SimpleGrid cols={2} spacing="sm">
|
<SimpleGrid cols={2} spacing="sm">
|
||||||
<TextInput label="From" type="date" />
|
<AmharicDatePicker label="From" value={fromDate} onChange={setFromDate} />
|
||||||
<TextInput label="To" type="date" />
|
<AmharicDatePicker label="To" value={toDate} onChange={setToDate} />
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
<TextInput label="Engagement Port" placeholder="Port name" />
|
<TextInput label="Engagement Port" placeholder="Port name" />
|
||||||
<Group justify="flex-end" mt="sm">
|
<Group justify="flex-end" mt="sm">
|
||||||
@@ -534,6 +543,9 @@ function AddSeaServiceModal({ opened, onClose }: { opened: boolean; onClose: ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
function AddCertModal({ opened, onClose }: { opened: boolean; onClose: () => void }) {
|
function AddCertModal({ opened, onClose }: { opened: boolean; onClose: () => void }) {
|
||||||
|
const [issueDate, setIssueDate] = useState('');
|
||||||
|
const [expiryDate, setExpiryDate] = useState('');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal opened={opened} onClose={onClose} title="Add Certification" size="lg">
|
<Modal opened={opened} onClose={onClose} title="Add Certification" size="lg">
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
@@ -544,8 +556,8 @@ function AddCertModal({ opened, onClose }: { opened: boolean; onClose: () => voi
|
|||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
<TextInput label="Issued By" placeholder="Issuing authority" />
|
<TextInput label="Issued By" placeholder="Issuing authority" />
|
||||||
<SimpleGrid cols={2} spacing="sm">
|
<SimpleGrid cols={2} spacing="sm">
|
||||||
<TextInput label="Issue Date" type="date" />
|
<AmharicDatePicker label="Issue Date" value={issueDate} onChange={setIssueDate} />
|
||||||
<TextInput label="Expiry Date" type="date" />
|
<AmharicDatePicker label="Expiry Date" value={expiryDate} onChange={setExpiryDate} />
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
<Select label="Status" data={['Valid', 'Expired', 'Pending']} defaultValue="Valid" />
|
<Select label="Status" data={['Valid', 'Expired', 'Pending']} defaultValue="Valid" />
|
||||||
<Group justify="flex-end" mt="sm">
|
<Group justify="flex-end" mt="sm">
|
||||||
|
|||||||
@@ -264,7 +264,7 @@ export function SeafarerRegistrationPage() {
|
|||||||
const [middleName, setMiddleName] = useState<BilingualValue>({ en: '', am: '' });
|
const [middleName, setMiddleName] = useState<BilingualValue>({ en: '', am: '' });
|
||||||
const [lastName, setLastName] = useState<BilingualValue>({ en: '', am: '' });
|
const [lastName, setLastName] = useState<BilingualValue>({ en: '', am: '' });
|
||||||
const [gender, setGender] = useState<string | null>(null);
|
const [gender, setGender] = useState<string | null>(null);
|
||||||
const [dob, setDob] = useState<Date | null>(null);
|
const [dob, setDob] = useState('');
|
||||||
const [placeOfBirth, setPlaceOfBirth] = useState('');
|
const [placeOfBirth, setPlaceOfBirth] = useState('');
|
||||||
const [nationality, setNationality] = useState<string | null>('Ethiopian');
|
const [nationality, setNationality] = useState<string | null>('Ethiopian');
|
||||||
const [maritalStatus, setMaritalStatus] = useState<string | null>(null);
|
const [maritalStatus, setMaritalStatus] = useState<string | null>(null);
|
||||||
@@ -307,7 +307,7 @@ export function SeafarerRegistrationPage() {
|
|||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
try {
|
try {
|
||||||
const result = await submitSeafarerRegistration({
|
const result = await submitSeafarerRegistration({
|
||||||
personalInfo: { firstName, middleName, lastName, gender, dob: dob?.toISOString().split('T')[0] ?? '', placeOfBirth, nationality, maritalStatus, nationalIdNumber, passportNumber, passportExpiry },
|
personalInfo: { firstName, middleName, lastName, gender, dob, placeOfBirth, nationality, maritalStatus, nationalIdNumber, passportNumber, passportExpiry },
|
||||||
contactDetails: { mobile, email, locationId, permanentAddress, currentAddress, emergency: { name: emergencyName, relationship: emergencyRel, phone: emergencyPhone } },
|
contactDetails: { mobile, email, locationId, permanentAddress, currentAddress, emergency: { name: emergencyName, relationship: emergencyRel, phone: emergencyPhone } },
|
||||||
documents: Object.fromEntries(Object.entries(files).map(([k, v]) => [k, v?.name ?? null])),
|
documents: Object.fromEntries(Object.entries(files).map(([k, v]) => [k, v?.name ?? null])),
|
||||||
});
|
});
|
||||||
@@ -365,7 +365,7 @@ export function SeafarerRegistrationPage() {
|
|||||||
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md">
|
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md">
|
||||||
<TextInput label="National ID Number" placeholder="ET-000000" required value={nationalIdNumber} onChange={(e) => setNationalIdNumber(e.currentTarget.value)} />
|
<TextInput label="National ID Number" placeholder="ET-000000" required value={nationalIdNumber} onChange={(e) => setNationalIdNumber(e.currentTarget.value)} />
|
||||||
<TextInput label="Passport Number" placeholder="EP000000" value={passportNumber} onChange={(e) => setPassportNumber(e.currentTarget.value)} />
|
<TextInput label="Passport Number" placeholder="EP000000" value={passportNumber} onChange={(e) => setPassportNumber(e.currentTarget.value)} />
|
||||||
<TextInput label="Passport Expiry Date" type="date" value={passportExpiry} onChange={(e) => setPassportExpiry(e.currentTarget.value)} />
|
<AmharicDatePicker label="Passport Expiry Date" value={passportExpiry} onChange={setPassportExpiry} />
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
|
|
||||||
<Alert variant="light" color="blue" icon={<IconInfoCircle size={17} />}>
|
<Alert variant="light" color="blue" icon={<IconInfoCircle size={17} />}>
|
||||||
@@ -458,7 +458,7 @@ export function SeafarerRegistrationPage() {
|
|||||||
<ReviewRow label="Middle Name" value={`${middleName.en}${middleName.am ? ` / ${middleName.am}` : ''}`} />
|
<ReviewRow label="Middle Name" value={`${middleName.en}${middleName.am ? ` / ${middleName.am}` : ''}`} />
|
||||||
<ReviewRow label="Last Name" value={`${lastName.en}${lastName.am ? ` / ${lastName.am}` : ''}`} />
|
<ReviewRow label="Last Name" value={`${lastName.en}${lastName.am ? ` / ${lastName.am}` : ''}`} />
|
||||||
<ReviewRow label="Gender" value={gender ?? ''} />
|
<ReviewRow label="Gender" value={gender ?? ''} />
|
||||||
<ReviewRow label="Date of Birth" value={`${dob?.toLocaleDateString('en-US') ?? ''}${dob ? ` (${toEthiopicDateLabel(dob)})` : ''}`} />
|
<ReviewRow label="Date of Birth" value={`${dob}${dob ? ` (${toEthiopicDateLabel(dob)})` : ''}`} />
|
||||||
<ReviewRow label="Place of Birth" value={placeOfBirth} />
|
<ReviewRow label="Place of Birth" value={placeOfBirth} />
|
||||||
<ReviewRow label="Nationality" value={nationality ?? ''} />
|
<ReviewRow label="Nationality" value={nationality ?? ''} />
|
||||||
<ReviewRow label="Marital Status" value={maritalStatus ?? ''} />
|
<ReviewRow label="Marital Status" value={maritalStatus ?? ''} />
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
|
import { AmharicDatePicker } from "../../../components/AmharicDatePicker";
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
Badge,
|
Badge,
|
||||||
@@ -315,20 +316,18 @@ function BSTCard({
|
|||||||
onChange={(e) => onIssuer(e.currentTarget.value)}
|
onChange={(e) => onIssuer(e.currentTarget.value)}
|
||||||
/>
|
/>
|
||||||
<SimpleGrid cols={slot.refreshYears > 0 ? 2 : 1} spacing="xs">
|
<SimpleGrid cols={slot.refreshYears > 0 ? 2 : 1} spacing="xs">
|
||||||
<TextInput
|
<AmharicDatePicker
|
||||||
label="Issue Date"
|
label="Issue Date"
|
||||||
type="date"
|
|
||||||
size="xs"
|
size="xs"
|
||||||
value={issueDate}
|
value={issueDate}
|
||||||
onChange={(e) => onIssueDate(e.currentTarget.value)}
|
onChange={onIssueDate}
|
||||||
/>
|
/>
|
||||||
{slot.refreshYears > 0 && (
|
{slot.refreshYears > 0 && (
|
||||||
<TextInput
|
<AmharicDatePicker
|
||||||
label={`Expiry (${slot.refreshYears}yr)`}
|
label={`Expiry (${slot.refreshYears}yr)`}
|
||||||
type="date"
|
|
||||||
size="xs"
|
size="xs"
|
||||||
value={expiryDate}
|
value={expiryDate}
|
||||||
onChange={(e) => onExpiryDate(e.currentTarget.value)}
|
onChange={onExpiryDate}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
@@ -665,19 +664,17 @@ export function SeamanBookApplicationPage() {
|
|||||||
/>
|
/>
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md">
|
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md">
|
||||||
<TextInput
|
<AmharicDatePicker
|
||||||
label="Issue Date"
|
label="Issue Date"
|
||||||
type="date"
|
|
||||||
required
|
required
|
||||||
value={medIssueDate}
|
value={medIssueDate}
|
||||||
onChange={(e) => setMedIssueDate(e.currentTarget.value)}
|
onChange={setMedIssueDate}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<AmharicDatePicker
|
||||||
label="Expiry Date"
|
label="Expiry Date"
|
||||||
type="date"
|
|
||||||
required
|
required
|
||||||
value={medExpiryDate}
|
value={medExpiryDate}
|
||||||
onChange={(e) => setMedExpiryDate(e.currentTarget.value)}
|
onChange={setMedExpiryDate}
|
||||||
/>
|
/>
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
<SectionHead title="Upload Certificate" />
|
<SectionHead title="Upload Certificate" />
|
||||||
@@ -1006,12 +1003,11 @@ export function SeamanBookApplicationPage() {
|
|||||||
value={paymentRef}
|
value={paymentRef}
|
||||||
onChange={(e) => setPaymentRef(e.currentTarget.value)}
|
onChange={(e) => setPaymentRef(e.currentTarget.value)}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<AmharicDatePicker
|
||||||
label="Payment Date"
|
label="Payment Date"
|
||||||
type="date"
|
|
||||||
required
|
required
|
||||||
value={paymentDate}
|
value={paymentDate}
|
||||||
onChange={(e) => setPaymentDate(e.currentTarget.value)}
|
onChange={setPaymentDate}
|
||||||
/>
|
/>
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useApiMutation } from '@ema-platform/api';
|
import { useApiMutation } from '@ema-platform/api';
|
||||||
|
import { AmharicDatePicker } from '../../../components/AmharicDatePicker';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
Badge,
|
Badge,
|
||||||
@@ -324,8 +325,8 @@ export function ShippingAgentLicenseApplicationPage() {
|
|||||||
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md">
|
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md">
|
||||||
<TextInput label="Shipping Company Name" required value={shippingCompanyName} onChange={(e) => setShippingCompanyName(e.currentTarget.value)} />
|
<TextInput label="Shipping Company Name" required value={shippingCompanyName} onChange={(e) => setShippingCompanyName(e.currentTarget.value)} />
|
||||||
<TextInput label="Agreement Reference Number" required value={agreementRefNumber} onChange={(e) => setAgreementRefNumber(e.currentTarget.value)} />
|
<TextInput label="Agreement Reference Number" required value={agreementRefNumber} onChange={(e) => setAgreementRefNumber(e.currentTarget.value)} />
|
||||||
<TextInput label="Agreement Start Date" type="date" required value={agreementStartDate} onChange={(e) => setAgreementStartDate(e.currentTarget.value)} />
|
<AmharicDatePicker label="Agreement Start Date" required value={agreementStartDate} onChange={setAgreementStartDate} />
|
||||||
<TextInput label="Agreement End Date" type="date" required value={agreementEndDate} onChange={(e) => setAgreementEndDate(e.currentTarget.value)} />
|
<AmharicDatePicker label="Agreement End Date" required value={agreementEndDate} onChange={setAgreementEndDate} />
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useApiMutation } from '@ema-platform/api';
|
import { useApiMutation } from '@ema-platform/api';
|
||||||
|
import { AmharicDatePicker } from '../../../components/AmharicDatePicker';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
Badge,
|
Badge,
|
||||||
@@ -372,7 +373,7 @@ export function WaiverApplicationPage() {
|
|||||||
<SectionHead title="Invoice Information" />
|
<SectionHead title="Invoice Information" />
|
||||||
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md">
|
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md">
|
||||||
<TextInput label="Invoice Number" required value={invoiceNumber} onChange={(e) => setInvoiceNumber(e.currentTarget.value)} />
|
<TextInput label="Invoice Number" required value={invoiceNumber} onChange={(e) => setInvoiceNumber(e.currentTarget.value)} />
|
||||||
<TextInput type="date" label="Invoice Date" required value={invoiceDate} onChange={(e) => setInvoiceDate(e.currentTarget.value)} />
|
<AmharicDatePicker label="Invoice Date" required value={invoiceDate} onChange={setInvoiceDate} />
|
||||||
<NumberInput label="Invoice Amount" required min={0} value={invoiceAmount} onChange={setInvoiceAmount} />
|
<NumberInput label="Invoice Amount" required min={0} value={invoiceAmount} onChange={setInvoiceAmount} />
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -393,10 +394,10 @@ export function WaiverApplicationPage() {
|
|||||||
<TextInput label="Shipping Line / Carrier Name" required value={carrierName} onChange={(e) => setCarrierName(e.currentTarget.value)} />
|
<TextInput label="Shipping Line / Carrier Name" required value={carrierName} onChange={(e) => setCarrierName(e.currentTarget.value)} />
|
||||||
<TextInput label="Bill of Lading Number" value={billOfLadingNumber} onChange={(e) => setBillOfLadingNumber(e.currentTarget.value)} />
|
<TextInput label="Bill of Lading Number" value={billOfLadingNumber} onChange={(e) => setBillOfLadingNumber(e.currentTarget.value)} />
|
||||||
{isPreWaiver && (
|
{isPreWaiver && (
|
||||||
<TextInput type="date" label="Estimated Arrival Date" required value={estimatedArrivalDate} onChange={(e) => setEstimatedArrivalDate(e.currentTarget.value)} />
|
<AmharicDatePicker label="Estimated Arrival Date" required value={estimatedArrivalDate} onChange={setEstimatedArrivalDate} />
|
||||||
)}
|
)}
|
||||||
{isPostWaiver && (
|
{isPostWaiver && (
|
||||||
<TextInput type="date" label="Actual Arrival Date" required value={actualArrivalDate} onChange={(e) => setActualArrivalDate(e.currentTarget.value)} />
|
<AmharicDatePicker label="Actual Arrival Date" required value={actualArrivalDate} onChange={setActualArrivalDate} />
|
||||||
)}
|
)}
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ export const am: Translations = {
|
|||||||
learnMore: 'ተጨማሪ ይወቁ',
|
learnMore: 'ተጨማሪ ይወቁ',
|
||||||
toggleTheme: 'ብርሃን / ጨለማ ገጽታ ቀይር',
|
toggleTheme: 'ብርሃን / ጨለማ ገጽታ ቀይር',
|
||||||
welcome: 'እንኳን ደህና መጡ',
|
welcome: 'እንኳን ደህና መጡ',
|
||||||
|
switchCalendar: 'የቀን መቁጠሪያ ዓይነት ቀይር',
|
||||||
},
|
},
|
||||||
|
|
||||||
auth: {
|
auth: {
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ export const en = {
|
|||||||
learnMore: 'Learn more',
|
learnMore: 'Learn more',
|
||||||
toggleTheme: 'Toggle light / dark mode',
|
toggleTheme: 'Toggle light / dark mode',
|
||||||
welcome: 'Welcome',
|
welcome: 'Welcome',
|
||||||
|
switchCalendar: 'Switch calendar type',
|
||||||
},
|
},
|
||||||
|
|
||||||
auth: {
|
auth: {
|
||||||
|
|||||||
69
package-lock.json
generated
69
package-lock.json
generated
@@ -25,6 +25,7 @@
|
|||||||
"country-flag-icons": "^1.6.20",
|
"country-flag-icons": "^1.6.20",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"dayjs": "^1.11.20",
|
"dayjs": "^1.11.20",
|
||||||
|
"ethiopian-calendar-date-converter": "^2.1.6",
|
||||||
"i18n-iso-countries": "^7.14.0",
|
"i18n-iso-countries": "^7.14.0",
|
||||||
"i18next": "^25.6.0",
|
"i18next": "^25.6.0",
|
||||||
"js-cookie": "^3.0.8",
|
"js-cookie": "^3.0.8",
|
||||||
@@ -2043,7 +2044,7 @@
|
|||||||
"version": "1.10.0",
|
"version": "1.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
|
||||||
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
|
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emnapi/wasi-threads": "1.2.1",
|
"@emnapi/wasi-threads": "1.2.1",
|
||||||
@@ -2054,7 +2055,7 @@
|
|||||||
"version": "1.10.0",
|
"version": "1.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
|
||||||
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
|
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
@@ -2064,7 +2065,7 @@
|
|||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
|
||||||
"integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
|
"integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
@@ -4133,6 +4134,7 @@
|
|||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz",
|
||||||
"integrity": "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==",
|
"integrity": "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -8403,6 +8405,66 @@
|
|||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": {
|
||||||
|
"version": "1.10.0",
|
||||||
|
"inBundle": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@emnapi/wasi-threads": "1.2.1",
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": {
|
||||||
|
"version": "1.10.0",
|
||||||
|
"inBundle": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"inBundle": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"inBundle": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@tybys/wasm-util": "^0.10.1"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/Brooooooklyn"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@emnapi/core": "^1.7.1",
|
||||||
|
"@emnapi/runtime": "^1.7.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": {
|
||||||
|
"version": "0.10.2",
|
||||||
|
"inBundle": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": {
|
||||||
|
"version": "2.8.1",
|
||||||
|
"inBundle": true,
|
||||||
|
"license": "0BSD",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
|
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
|
||||||
"version": "4.3.1",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.1.tgz",
|
||||||
@@ -8950,6 +9012,7 @@
|
|||||||
"version": "0.10.2",
|
"version": "0.10.2",
|
||||||
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
|
||||||
"integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
|
"integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
"country-flag-icons": "^1.6.20",
|
"country-flag-icons": "^1.6.20",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"dayjs": "^1.11.20",
|
"dayjs": "^1.11.20",
|
||||||
|
"ethiopian-calendar-date-converter": "^2.1.6",
|
||||||
"i18n-iso-countries": "^7.14.0",
|
"i18n-iso-countries": "^7.14.0",
|
||||||
"i18next": "^25.6.0",
|
"i18next": "^25.6.0",
|
||||||
"js-cookie": "^3.0.8",
|
"js-cookie": "^3.0.8",
|
||||||
|
|||||||
Reference in New Issue
Block a user