improvement: some improvement done for appointment and treatment shared components.

This commit is contained in:
2026-07-17 11:21:08 +03:30
parent d2ad1fd7b6
commit 1b63bfff00
12 changed files with 204 additions and 38 deletions

View File

@@ -6,6 +6,7 @@ import { CalendarDays } from 'lucide-react';
import { parseDateInput, startOfLocalDay, toDateInputValue } from '@/components/appointments/appointmentTime';
import { FORM_DATE_INPUT_CLASS } from '@/components/shared/formSelectStyles';
import { CalendarDayPartsPanel } from '@/components/ui/shared/CalendarDayPartsPanel';
import { useAnchoredPanelPosition } from '@/lib/hooks/useAnchoredPanelPosition';
import {
formatIsoAsGregorianDateInput,
maskGregorianDateTyping,
@@ -45,6 +46,11 @@ export function AppDateInput({
const rootRef = useRef<HTMLDivElement>(null);
const [text, setText] = useState('');
const [panelOpen, setPanelOpen] = useState(false);
const { panelRef, style: panelStyle } = useAnchoredPanelPosition({
open: panelOpen && !disabled,
anchorRef: rootRef,
align: 'start',
});
useEffect(() => {
setText(
@@ -56,9 +62,11 @@ export function AppDateInput({
if (!panelOpen) return;
function onPointerDown(event: MouseEvent) {
if (!rootRef.current?.contains(event.target as Node)) {
setPanelOpen(false);
const target = event.target as Node;
if (rootRef.current?.contains(target) || panelRef.current?.contains(target)) {
return;
}
setPanelOpen(false);
}
function onKeyDown(event: KeyboardEvent) {
@@ -73,7 +81,7 @@ export function AppDateInput({
document.removeEventListener('mousedown', onPointerDown);
document.removeEventListener('keydown', onKeyDown);
};
}, [panelOpen]);
}, [panelOpen, panelRef]);
const panelAnchorDate = value ? parseDateInput(value) : startOfLocalDay(new Date());
const placeholder = persian ? '۱۴۰۴/۰۴/۲۲' : '2026-07-13';
@@ -154,9 +162,19 @@ export function AppDateInput({
{panelOpen && !disabled ? (
<div
ref={panelRef}
id={`${panelId}-parts`}
role="dialog"
className="absolute start-0 top-full z-50 mt-1 min-w-[17.5rem] w-max max-w-[calc(100vw-1.5rem)] rounded-[var(--radius-md)] border border-border bg-background-secondary p-3 shadow-lg"
style={
panelStyle ?? {
position: 'fixed',
top: 0,
left: 0,
visibility: 'hidden',
pointerEvents: 'none',
}
}
className="min-w-[17.5rem] rounded-[var(--radius-md)] border border-border bg-background-secondary p-3 shadow-lg"
>
<CalendarDayPartsPanel
panelId={panelId}

View File

@@ -8,6 +8,7 @@ import { formatAppPickerDateLabel } from '@/lib/i18n/format';
import { CalendarDayPartsPanel } from '@/components/ui/shared/CalendarDayPartsPanel';
import { addCalendarDays, compareLocalDayStart, startOfLocalDay } from '@/components/appointments/appointmentTime';
import { Checkbox } from '@/components/ui/shared/Checkbox';
import { useAnchoredPanelPosition } from '@/lib/hooks/useAnchoredPanelPosition';
export type CalendarDaySelectProps = {
value: Date;
@@ -50,6 +51,11 @@ export function CalendarDaySelect({
const panelId = useId();
const rootRef = useRef<HTMLDivElement>(null);
const [panelOpen, setPanelOpen] = useState(false);
const { panelRef, style: panelStyle } = useAnchoredPanelPosition({
open: panelOpen && !disabled,
anchorRef: rootRef,
align: 'stretch',
});
const normalizedValue = startOfLocalDay(value);
const today = startOfLocalDay(new Date());
@@ -63,10 +69,12 @@ export function CalendarDaySelect({
if (!panelOpen) return;
function onPointerDown(event: MouseEvent) {
if (!rootRef.current?.contains(event.target as Node)) {
setPanelOpen(false);
onBlur?.();
const target = event.target as Node;
if (rootRef.current?.contains(target) || panelRef.current?.contains(target)) {
return;
}
setPanelOpen(false);
onBlur?.();
}
function onKeyDown(event: KeyboardEvent) {
@@ -82,7 +90,7 @@ export function CalendarDaySelect({
document.removeEventListener('mousedown', onPointerDown);
document.removeEventListener('keydown', onKeyDown);
};
}, [onBlur, panelOpen]);
}, [onBlur, panelOpen, panelRef]);
const triggerButton = (
<button
@@ -166,17 +174,27 @@ export function CalendarDaySelect({
{panelOpen && !disabled ? (
<div
ref={panelRef}
id={panelId}
role="dialog"
aria-label={t('chooseDate')}
className="absolute left-0 right-0 top-full z-50 mt-2 rounded-[var(--radius-md)] border border-border bg-background-secondary p-3 shadow-lg"
style={
panelStyle ?? {
position: 'fixed',
top: 0,
left: 0,
visibility: 'hidden',
pointerEvents: 'none',
}
}
className="rounded-[var(--radius-md)] border border-border bg-background-secondary p-3 shadow-lg"
>
<CalendarDayPartsPanel
panelId={panelId}
value={normalizedValue}
onChange={onChange}
closePanelOnDaySelect={closePanelOnDaySelect}
onAfterSelect={(day) => {
onAfterSelect={() => {
setPanelOpen(false);
onBlur?.();
}}