-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
401 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import type { QueryRecords } from '@egodb/core' | ||
import type { ICalendarField } from '@egodb/core/view/calendar' | ||
import { Calendar, Container } from '@egodb/ui' | ||
import { useSetAtom } from 'jotai' | ||
import { useState } from 'react' | ||
import { createRecordInitialValueAtom } from '../create-record-form/create-record-initial-value.atom' | ||
import { createRecordFormDrawerOpened } from '../create-record-form/drawer-opened.atom' | ||
import type { ITableBaseProps } from '../table/table-base-props' | ||
import { Day } from './day' | ||
|
||
interface IProps extends ITableBaseProps { | ||
field: ICalendarField | ||
records: QueryRecords | ||
} | ||
|
||
export const CalendarBoard: React.FC<IProps> = ({ field }) => { | ||
const [date, setDate] = useState<Date | null>(null) | ||
const setOpened = useSetAtom(createRecordFormDrawerOpened) | ||
const setInitialValue = useSetAtom(createRecordInitialValueAtom) | ||
|
||
const onChange = (date: Date) => { | ||
setDate(date) | ||
setOpened(true) | ||
setInitialValue({ [field.name.value]: date }) | ||
} | ||
|
||
return ( | ||
<Container w="100%" h="100%" maw="100%" p={0}> | ||
<Calendar | ||
value={date} | ||
onChange={onChange} | ||
h="100%" | ||
bg="white" | ||
fullWidth | ||
size="xl" | ||
allowLevelChange={false} | ||
renderDay={(date) => <Day date={date} />} | ||
styles={(theme) => ({ | ||
calendarHeader: { | ||
height: 30, | ||
marginBottom: 0, | ||
paddingBottom: 10, | ||
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[5] : theme.colors.gray[0], | ||
}, | ||
calendarHeaderControl: { | ||
height: '100%', | ||
}, | ||
calendarHeaderLevel: { | ||
height: '100%', | ||
fontSize: theme.fontSizes.md, | ||
}, | ||
month: { height: 'calc(100% - 40px)' }, | ||
cell: { | ||
border: `1px solid ${theme.colorScheme === 'dark' ? theme.colors.dark[4] : theme.colors.gray[1]}`, | ||
}, | ||
day: { | ||
padding: theme.spacing.xs, | ||
borderRadius: 0, | ||
height: '100%', | ||
display: 'inline-flex', | ||
flexDirection: 'column', | ||
fontSize: theme.fontSizes.sm, | ||
}, | ||
weekday: { fontSize: theme.fontSizes.lg }, | ||
weekdayCell: { | ||
fontSize: theme.fontSizes.xs, | ||
border: `1px solid ${theme.colorScheme === 'dark' ? theme.colors.dark[4] : theme.colors.gray[1]}`, | ||
height: 20, | ||
}, | ||
})} | ||
/> | ||
</Container> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { atom } from 'jotai' | ||
|
||
export const calendarStep = atom(0) | ||
|
||
export const calendarStepZero = atom(null, (get, set) => set(calendarStep, 0)) | ||
export const calendarStepOne = atom(null, (get, set) => set(calendarStep, 1)) | ||
export const calendarStepTwo = atom(null, (get, set) => set(calendarStep, 2)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,60 +1,27 @@ | ||
import type { QueryRecords } from '@egodb/core' | ||
import { Calendar, Container } from '@egodb/ui' | ||
import { useState } from 'react' | ||
import type { ICalendarField } from '@egodb/core/view/calendar' | ||
import { Center, Container } from '@egodb/ui' | ||
import type { ITableBaseProps } from '../table/table-base-props' | ||
import { Day } from './day' | ||
import { CalendarBoard } from './calendar-board' | ||
import { SelectCalendarField } from './select-calendar-field' | ||
|
||
interface IProps extends ITableBaseProps { | ||
records: QueryRecords | ||
} | ||
|
||
export const CalendarUI: React.FC<IProps> = () => { | ||
const [date, setDate] = useState<Date | null>(null) | ||
export const CalendarUI: React.FC<IProps> = ({ table, records }) => { | ||
const view = table.mustGetView() | ||
const calendarFieldId = view.calendarFieldId.into() | ||
if (calendarFieldId) { | ||
const field = table.schema.getFieldById(calendarFieldId.value).into() as ICalendarField | ||
return <CalendarBoard table={table} records={records} field={field} /> | ||
} | ||
|
||
return ( | ||
<Container w="100%" h="100%" maw="100%" p={0}> | ||
<Calendar | ||
value={date} | ||
onChange={setDate} | ||
h="100%" | ||
bg="white" | ||
fullWidth | ||
size="xl" | ||
allowLevelChange={false} | ||
renderDay={(date) => <Day date={date} />} | ||
styles={(theme) => ({ | ||
calendarHeader: { | ||
height: 30, | ||
marginBottom: 0, | ||
paddingBottom: 10, | ||
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[5] : theme.colors.gray[0], | ||
}, | ||
calendarHeaderControl: { | ||
height: '100%', | ||
}, | ||
calendarHeaderLevel: { | ||
height: '100%', | ||
fontSize: theme.fontSizes.md, | ||
}, | ||
month: { height: 'calc(100% - 40px)' }, | ||
cell: { | ||
border: `1px solid ${theme.colorScheme === 'dark' ? theme.colors.dark[4] : theme.colors.gray[1]}`, | ||
}, | ||
day: { | ||
padding: theme.spacing.xs, | ||
borderRadius: 0, | ||
height: '100%', | ||
display: 'inline-flex', | ||
flexDirection: 'column', | ||
fontSize: theme.fontSizes.sm, | ||
}, | ||
weekday: { fontSize: theme.fontSizes.lg }, | ||
weekdayCell: { | ||
fontSize: theme.fontSizes.xs, | ||
border: `1px solid ${theme.colorScheme === 'dark' ? theme.colors.dark[4] : theme.colors.gray[1]}`, | ||
height: 20, | ||
}, | ||
})} | ||
/> | ||
<Container h="100%" w={450}> | ||
<Center h="100%" w="100%"> | ||
<SelectCalendarField table={table} /> | ||
</Center> | ||
</Container> | ||
) | ||
} |
92 changes: 92 additions & 0 deletions
92
apps/web/components/calendar-ui/create-calendar-date-field.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import type { ICreateDateFieldSchema } from '@egodb/core' | ||
import { createDateFieldSchema, FieldId } from '@egodb/core' | ||
import { | ||
Button, | ||
Card, | ||
FocusTrap, | ||
Group, | ||
IconChevronLeft, | ||
Stack, | ||
Text, | ||
TextInput, | ||
useForm, | ||
zodResolver, | ||
} from '@egodb/ui' | ||
import { useSetAtom } from 'jotai' | ||
import { trpc } from '../../trpc' | ||
import type { ITableBaseProps } from '../table/table-base-props' | ||
import { calendarStepZero } from './calendar-step.atom' | ||
|
||
interface IProps extends ITableBaseProps { | ||
onSuccess?: () => void | ||
} | ||
|
||
export const CreateCalendarDateField: React.FC<IProps> = ({ table, onSuccess }) => { | ||
const form = useForm<ICreateDateFieldSchema>({ | ||
initialValues: { | ||
type: 'date', | ||
id: 'id', | ||
name: '', | ||
}, | ||
validate: zodResolver(createDateFieldSchema), | ||
}) | ||
|
||
const utils = trpc.useContext() | ||
|
||
const setCalendarField = trpc.table.view.calendar.setField.useMutation({ | ||
onSuccess() { | ||
utils.table.get.refetch() | ||
setStepZero() | ||
onSuccess?.() | ||
}, | ||
}) | ||
|
||
const createDateField = trpc.table.field.create.useMutation({ | ||
onSuccess(_, variables) { | ||
const id = variables.field.id | ||
|
||
setCalendarField.mutate({ | ||
tableId: table.id.value, | ||
field: id, | ||
}) | ||
}, | ||
}) | ||
|
||
const onSubmit = form.onSubmit((values) => { | ||
createDateField.mutate({ | ||
id: table.id.value, | ||
field: { ...values, id: FieldId.create().value }, | ||
}) | ||
}) | ||
|
||
const setStepZero = useSetAtom(calendarStepZero) | ||
|
||
return ( | ||
<form onSubmit={onSubmit}> | ||
<Card shadow="sm"> | ||
<Card.Section withBorder inheritPadding py="sm"> | ||
<Text>create new date field</Text> | ||
</Card.Section> | ||
|
||
<Card.Section withBorder inheritPadding py="sm"> | ||
<Stack spacing="xs"> | ||
<FocusTrap> | ||
<TextInput {...form.getInputProps('name')} placeholder="new date field name" /> | ||
</FocusTrap> | ||
</Stack> | ||
</Card.Section> | ||
|
||
<Card.Section withBorder inheritPadding py="sm"> | ||
<Group position="right"> | ||
<Button leftIcon={<IconChevronLeft size={14} />} size="xs" variant="white" onClick={setStepZero}> | ||
Select Existing Field | ||
</Button> | ||
<Button size="xs" type="submit" disabled={!form.isValid()}> | ||
Done | ||
</Button> | ||
</Group> | ||
</Card.Section> | ||
</Card> | ||
</form> | ||
) | ||
} |
93 changes: 93 additions & 0 deletions
93
apps/web/components/calendar-ui/create-calendar-date-range-field.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import type { ICreateDateRangeFieldSchema } from '@egodb/core' | ||
import { createDateRangeFieldSchema } from '@egodb/core' | ||
import { FieldId } from '@egodb/core' | ||
import { | ||
Button, | ||
Card, | ||
FocusTrap, | ||
Group, | ||
IconChevronLeft, | ||
Stack, | ||
Text, | ||
TextInput, | ||
useForm, | ||
zodResolver, | ||
} from '@egodb/ui' | ||
import { useSetAtom } from 'jotai' | ||
import { trpc } from '../../trpc' | ||
import type { ITableBaseProps } from '../table/table-base-props' | ||
import { calendarStepZero } from './calendar-step.atom' | ||
|
||
interface IProps extends ITableBaseProps { | ||
onSuccess?: () => void | ||
} | ||
|
||
export const CreateCalendarDateRangeField: React.FC<IProps> = ({ table, onSuccess }) => { | ||
const form = useForm<ICreateDateRangeFieldSchema>({ | ||
initialValues: { | ||
type: 'date-range', | ||
id: 'id', | ||
name: '', | ||
}, | ||
validate: zodResolver(createDateRangeFieldSchema), | ||
}) | ||
|
||
const utils = trpc.useContext() | ||
|
||
const setCalendarField = trpc.table.view.calendar.setField.useMutation({ | ||
onSuccess() { | ||
utils.table.get.refetch() | ||
setStepZero() | ||
onSuccess?.() | ||
}, | ||
}) | ||
|
||
const createDateRangeField = trpc.table.field.create.useMutation({ | ||
onSuccess(_, variables) { | ||
const id = variables.field.id | ||
|
||
setCalendarField.mutate({ | ||
tableId: table.id.value, | ||
field: id, | ||
}) | ||
}, | ||
}) | ||
|
||
const onSubmit = form.onSubmit((values) => { | ||
createDateRangeField.mutate({ | ||
id: table.id.value, | ||
field: { ...values, id: FieldId.create().value }, | ||
}) | ||
}) | ||
|
||
const setStepZero = useSetAtom(calendarStepZero) | ||
|
||
return ( | ||
<form onSubmit={onSubmit}> | ||
<Card shadow="sm"> | ||
<Card.Section withBorder inheritPadding py="sm"> | ||
<Text>create new date range field</Text> | ||
</Card.Section> | ||
|
||
<Card.Section withBorder inheritPadding py="sm"> | ||
<Stack spacing="xs"> | ||
<FocusTrap> | ||
<TextInput {...form.getInputProps('name')} placeholder="new date range field name" /> | ||
</FocusTrap> | ||
</Stack> | ||
</Card.Section> | ||
|
||
<Card.Section withBorder inheritPadding py="sm"> | ||
<Group position="right"> | ||
<Button leftIcon={<IconChevronLeft size={14} />} size="xs" variant="white" onClick={setStepZero}> | ||
Select Existing Field | ||
</Button> | ||
<Button size="xs" type="submit" disabled={!form.isValid()}> | ||
Done | ||
</Button> | ||
</Group> | ||
</Card.Section> | ||
</Card> | ||
</form> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { useAtomValue } from 'jotai' | ||
import type { ITableBaseProps } from '../table/table-base-props' | ||
import { calendarStep } from './calendar-step.atom' | ||
import { CreateCalendarDateField } from './create-calendar-date-field' | ||
import { CreateCalendarDateRangeField } from './create-calendar-date-range-field' | ||
import { SelectExistingCalendarField } from './select-existing-calendar-field' | ||
|
||
interface IProps extends ITableBaseProps { | ||
onSuccess?: () => void | ||
} | ||
|
||
export const SelectCalendarField: React.FC<IProps> = ({ table, onSuccess }) => { | ||
const step = useAtomValue(calendarStep) | ||
|
||
return ( | ||
<> | ||
{step === 0 ? <SelectExistingCalendarField onSuccess={onSuccess} table={table} /> : null} | ||
{step === 1 ? <CreateCalendarDateField onSuccess={onSuccess} table={table} /> : null} | ||
{step === 2 ? <CreateCalendarDateRangeField onSuccess={onSuccess} table={table} /> : null} | ||
</> | ||
) | ||
} |
Oops, something went wrong.