From 8a577dea735c598de2c49b452a4c36bea4a7208b Mon Sep 17 00:00:00 2001 From: Nevo David Date: Mon, 19 Jan 2026 14:55:07 +0700 Subject: [PATCH] feat: time table improvements --- .../src/components/launches/menu/menu.tsx | 2 +- .../src/components/launches/time.table.tsx | 178 +++++++++++------- 2 files changed, 115 insertions(+), 65 deletions(-) diff --git a/apps/frontend/src/components/launches/menu/menu.tsx b/apps/frontend/src/components/launches/menu/menu.tsx index 647c9165..e3d92045 100644 --- a/apps/frontend/src/components/launches/menu/menu.tsx +++ b/apps/frontend/src/components/launches/menu/menu.tsx @@ -168,7 +168,7 @@ export const Menu: FC<{ (integration) => integration.id === id ); modal.openModal({ - withCloseButton: false, + withCloseButton: true, closeOnEscape: false, closeOnClickOutside: false, askClose: true, diff --git a/apps/frontend/src/components/launches/time.table.tsx b/apps/frontend/src/components/launches/time.table.tsx index ea2fca3b..3e878a52 100644 --- a/apps/frontend/src/components/launches/time.table.tsx +++ b/apps/frontend/src/components/launches/time.table.tsx @@ -1,6 +1,6 @@ 'use client'; -import React, { FC, Fragment, useCallback, useMemo, useState } from 'react'; +import React, { FC, useCallback, useMemo, useState } from 'react'; import { Integrations } from '@gitroom/frontend/components/launches/calendar.context'; import dayjs from 'dayjs'; import { deleteDialog } from '@gitroom/react/helpers/delete.dialog'; @@ -16,14 +16,24 @@ import { sortBy } from 'lodash'; import { usePreventWindowUnload } from '@gitroom/react/helpers/use.prevent.window.unload'; import { useT } from '@gitroom/react/translation/get.transation.service.client'; import { newDayjs } from '@gitroom/frontend/components/layout/set.timezone'; +import clsx from 'clsx'; +import { + TrashIcon, + PlusIcon, + DelayIcon, +} from '@gitroom/frontend/components/ui/icons'; + dayjs.extend(utc); dayjs.extend(timezone); -const hours = [...Array(24).keys()].map((i, index) => ({ - value: index, + +const hours = [...Array(24).keys()].map((i) => ({ + value: i, })); -const minutes = [...Array(60).keys()].map((i, index) => ({ - value: index, + +const minutes = [...Array(60).keys()].map((i) => ({ + value: i, })); + export const TimeTable: FC<{ integration: Integrations; mutate: () => void; @@ -39,6 +49,7 @@ export const TimeTable: FC<{ const fetch = useFetch(); const modal = useModals(); usePreventWindowUnload(true); + const askClose = useCallback(async () => { if ( !(await deleteDialog( @@ -53,7 +64,9 @@ export const TimeTable: FC<{ } modal.closeAll(); }, []); + useKeypress('Escape', askClose); + const removeSlot = useCallback( (index: number) => async () => { if ( @@ -70,6 +83,7 @@ export const TimeTable: FC<{ }, [] ); + const addHour = useCallback(() => { const calculateMinutes = newDayjs() @@ -77,7 +91,8 @@ export const TimeTable: FC<{ .startOf('day') .add(hour, 'hours') .add(minute, 'minutes') - .diff(newDayjs().utc().startOf('day'), 'minutes') - dayjs.tz().utcOffset(); + .diff(newDayjs().utc().startOf('day'), 'minutes') - + dayjs.tz().utcOffset(); setCurrentTimes((prev) => [ ...prev, { @@ -85,6 +100,7 @@ export const TimeTable: FC<{ }, ]); }, [hour, minute]); + const times = useMemo(() => { return sortBy( currentTimes.map(({ time }) => ({ @@ -99,6 +115,7 @@ export const TimeTable: FC<{ (p) => p.value ); }, [currentTimes]); + const save = useCallback(async () => { await fetch(`/integrations/${props.integration.id}/time`, { method: 'POST', @@ -109,72 +126,105 @@ export const TimeTable: FC<{ mutate(); modal.closeAll(); }, [currentTimes]); + return ( -
-
-
+
+ {/* Add Time Slot Section */} +
+
+ {t('add_time_slot', 'Add Time Slot')}
-
-
-
- -
-
- -
+ +
+
+
-
- +
+
+
-
- {times.map((timeSlot, index) => ( - -
{timeSlot.formatted}
-
- X -
-
- ))} + + {/* Time Slots List */} +
+
+ {t('scheduled_times', 'Scheduled Times')} ({times.length}) +
+ + {times.length === 0 ? ( +
+ {t('no_time_slots', 'No time slots added yet')} +
+ ) : ( +
+ {times.map((timeSlot, index) => ( +
+
+
+ + {timeSlot.formatted} + +
+ +
+ ))} +
+ )}
-
-