test: add event creation test
This commit is contained in:
parent
dbf9809c7b
commit
1ec636f3b0
9 changed files with 251 additions and 189 deletions
|
@ -1,12 +0,0 @@
|
||||||
export default function authUser() {
|
|
||||||
cy.visit('http://127.0.0.1:3000/login');
|
|
||||||
cy.getBySel('login-header').should('exist');
|
|
||||||
cy.getBySel('login-form').should('exist');
|
|
||||||
cy.getBySel('email-input').should('exist');
|
|
||||||
cy.getBySel('password-input').should('exist');
|
|
||||||
cy.getBySel('login-button').should('exist');
|
|
||||||
cy.getBySel('email-input').type('cypress@example.com');
|
|
||||||
cy.getBySel('password-input').type('Password123!');
|
|
||||||
cy.getBySel('login-button').click();
|
|
||||||
cy.url().should('include', '/home');
|
|
||||||
}
|
|
|
@ -1,9 +1,40 @@
|
||||||
import authUser from './auth-user';
|
|
||||||
|
|
||||||
describe('event creation', () => {
|
describe('event creation', () => {
|
||||||
it('loads', () => {
|
it('loads', () => {
|
||||||
authUser();
|
cy.login();
|
||||||
|
|
||||||
// cy.visit('http://127.0.0.1:3000/events/new'); // TODO: Add event creation tests
|
cy.visit('http://127.0.0.1:3000/events/new');
|
||||||
|
cy.getBySel('event-form').should('exist');
|
||||||
|
cy.getBySel('event-form').within(() => {
|
||||||
|
cy.getBySel('event-name-input').should('exist');
|
||||||
|
cy.getBySel('event-start-time-picker').should('exist');
|
||||||
|
cy.getBySel('event-end-time-picker').should('exist');
|
||||||
|
cy.getBySel('event-location-input').should('exist');
|
||||||
|
cy.getBySel('event-description-input').should('exist');
|
||||||
|
cy.getBySel('event-save-button').should('exist');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates an event', () => {
|
||||||
|
cy.login();
|
||||||
|
cy.visit(
|
||||||
|
'http://127.0.0.1:3000/events/new?start=2025-07-01T01:00:00.000Z&end=2025-07-01T04:30:00.000Z',
|
||||||
|
);
|
||||||
|
|
||||||
|
cy.getBySel('event-form').should('exist');
|
||||||
|
cy.getBySel('event-form').within(() => {
|
||||||
|
cy.getBySel('event-name-input').type('Cypress Test Event');
|
||||||
|
cy.getBySel('event-location-input').type('Cypress Park');
|
||||||
|
cy.getBySel('event-description-input').type(
|
||||||
|
'This is a test event created by Cypress.',
|
||||||
|
);
|
||||||
|
cy.getBySel('event-save-button').click();
|
||||||
|
});
|
||||||
|
cy.wait(1000);
|
||||||
|
cy.visit('http://127.0.0.1:3000/events');
|
||||||
|
cy.getBySel('event-list-entry').should('exist');
|
||||||
|
cy.getBySel('event-list-entry')
|
||||||
|
.contains('Cypress Test Event')
|
||||||
|
.should('exist');
|
||||||
|
cy.getBySel('event-list-entry').contains('Cypress Park').should('exist');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
/* eslint-disable @typescript-eslint/no-namespace */
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
// ***********************************************
|
// ***********************************************
|
||||||
// This example commands.ts shows you how to
|
// This example commands.ts shows you how to
|
||||||
|
@ -44,6 +46,22 @@ Cypress.Commands.add('getBySelLike', (selector, ...args) => {
|
||||||
return cy.get(`[data-cy*=${selector}]`, ...args);
|
return cy.get(`[data-cy*=${selector}]`, ...args);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Cypress.Commands.add('login', () => {
|
||||||
|
cy.session('auth', () => {
|
||||||
|
cy.visit('http://127.0.0.1:3000/login');
|
||||||
|
cy.getBySel('login-header').should('exist');
|
||||||
|
cy.getBySel('login-form').should('exist');
|
||||||
|
cy.getBySel('email-input').should('exist');
|
||||||
|
cy.getBySel('password-input').should('exist');
|
||||||
|
cy.getBySel('login-button').should('exist');
|
||||||
|
cy.getBySel('email-input').type('cypress@example.com');
|
||||||
|
cy.getBySel('password-input').type('Password123!');
|
||||||
|
cy.getBySel('login-button').click();
|
||||||
|
cy.url().should('include', '/home');
|
||||||
|
cy.getBySel('header').should('exist');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
namespace Cypress {
|
namespace Cypress {
|
||||||
interface Chainable {
|
interface Chainable {
|
||||||
|
@ -55,6 +73,7 @@ declare global {
|
||||||
selector: string,
|
selector: string,
|
||||||
...args: any[]
|
...args: any[]
|
||||||
): Chainable<JQuery<HTMLElement>>;
|
): Chainable<JQuery<HTMLElement>>;
|
||||||
|
login(): Chainable<void>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,10 @@ export default function Events() {
|
||||||
const events = eventsData?.data?.events || [];
|
const events = eventsData?.data?.events || [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='relative h-full flex flex-col items-center'>
|
<div
|
||||||
|
className='relative h-full flex flex-col items-center'
|
||||||
|
data-cy='events-page'
|
||||||
|
>
|
||||||
{/* Heading */}
|
{/* Heading */}
|
||||||
<h1 className='text-3xl font-bold mt-8 mb-4 text-center z-10'>
|
<h1 className='text-3xl font-bold mt-8 mb-4 text-center z-10'>
|
||||||
My Events
|
My Events
|
||||||
|
|
|
@ -43,7 +43,10 @@ export default function EventListEntry({
|
||||||
return (
|
return (
|
||||||
<Link href={`/events/${id}`} className='block'>
|
<Link href={`/events/${id}`} className='block'>
|
||||||
<Card className='w-full'>
|
<Card className='w-full'>
|
||||||
<div className='grid grid-cols-1 gap-2 mx-auto md:mx-4 md:grid-cols-[80px_1fr_250px]'>
|
<div
|
||||||
|
className='grid grid-cols-1 gap-2 mx-auto md:mx-4 md:grid-cols-[80px_1fr_250px]'
|
||||||
|
data-cy='event-list-entry'
|
||||||
|
>
|
||||||
<div className='w-full items-center justify-center grid'>
|
<div className='w-full items-center justify-center grid'>
|
||||||
<Logo colorType='monochrome' logoType='submark' width={50} />
|
<Logo colorType='monochrome' logoType='submark' width={50} />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -17,6 +17,7 @@ export default function LabeledInput({
|
||||||
variantSize = 'default',
|
variantSize = 'default',
|
||||||
autocomplete,
|
autocomplete,
|
||||||
error,
|
error,
|
||||||
|
'data-cy': dataCy,
|
||||||
...rest
|
...rest
|
||||||
}: {
|
}: {
|
||||||
label: string;
|
label: string;
|
||||||
|
@ -30,6 +31,7 @@ export default function LabeledInput({
|
||||||
variantSize?: 'default' | 'big' | 'textarea';
|
variantSize?: 'default' | 'big' | 'textarea';
|
||||||
autocomplete?: string;
|
autocomplete?: string;
|
||||||
error?: string;
|
error?: string;
|
||||||
|
'data-cy'?: string;
|
||||||
} & React.InputHTMLAttributes<HTMLInputElement>) {
|
} & React.InputHTMLAttributes<HTMLInputElement>) {
|
||||||
const [passwordVisible, setPasswordVisible] = React.useState(false);
|
const [passwordVisible, setPasswordVisible] = React.useState(false);
|
||||||
const [inputValue, setInputValue] = React.useState(
|
const [inputValue, setInputValue] = React.useState(
|
||||||
|
@ -58,6 +60,7 @@ export default function LabeledInput({
|
||||||
id={name}
|
id={name}
|
||||||
name={name}
|
name={name}
|
||||||
rows={3}
|
rows={3}
|
||||||
|
data-cy={dataCy}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<span className='relative'>
|
<span className='relative'>
|
||||||
|
@ -76,6 +79,7 @@ export default function LabeledInput({
|
||||||
id={name}
|
id={name}
|
||||||
name={name}
|
name={name}
|
||||||
autoComplete={autocomplete}
|
autoComplete={autocomplete}
|
||||||
|
data-cy={dataCy}
|
||||||
{...rest}
|
{...rest}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -191,11 +191,6 @@ const EventForm: React.FC<EventFormProps> = (props) => {
|
||||||
router.back();
|
router.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate values for organiser, created, and updated
|
|
||||||
const organiserValue = isLoading
|
|
||||||
? 'Loading...'
|
|
||||||
: data?.data.user?.name || 'Unknown User';
|
|
||||||
|
|
||||||
// Use DB values for created_at/updated_at in edit mode
|
// Use DB values for created_at/updated_at in edit mode
|
||||||
const createdAtValue =
|
const createdAtValue =
|
||||||
props.type === 'edit' && event?.created_at
|
props.type === 'edit' && event?.created_at
|
||||||
|
@ -210,188 +205,203 @@ const EventForm: React.FC<EventFormProps> = (props) => {
|
||||||
const createdAtDisplay = new Date(createdAtValue).toLocaleDateString();
|
const createdAtDisplay = new Date(createdAtValue).toLocaleDateString();
|
||||||
const updatedAtDisplay = new Date(updatedAtValue).toLocaleDateString();
|
const updatedAtDisplay = new Date(updatedAtValue).toLocaleDateString();
|
||||||
|
|
||||||
|
const [isClient, setIsClient] = React.useState(false);
|
||||||
|
React.useEffect(() => {
|
||||||
|
setIsClient(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
if (props.type === 'edit' && isLoading) return <div>Loading...</div>;
|
if (props.type === 'edit' && isLoading) return <div>Loading...</div>;
|
||||||
if (props.type === 'edit' && fetchError)
|
if (props.type === 'edit' && fetchError)
|
||||||
return <div>Error loading event.</div>;
|
return <div>Error loading event.</div>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Dialog open={calendarOpen} onOpenChange={setCalendarOpen}>
|
||||||
<Dialog open={calendarOpen} onOpenChange={setCalendarOpen}>
|
<form
|
||||||
<form className='flex flex-col gap-5 w-full' onSubmit={handleSubmit}>
|
className='flex flex-col gap-5 w-full'
|
||||||
<div className='grid grid-row-start:auto gap-4 sm:gap-8 w-full'>
|
onSubmit={handleSubmit}
|
||||||
<div className='h-full w-full mt-0 ml-2 mb-16 flex items-center max-sm:grid max-sm:grid-row-start:auto max-sm:mb-6 max-sm:mt-10 max-sm:ml-0'>
|
data-cy='event-form'
|
||||||
<div className='w-[100px] max-sm:w-full max-sm:flex max-sm:justify-center'>
|
>
|
||||||
<Logo colorType='monochrome' logoType='submark' width={50} />
|
<div className='grid grid-row-start:auto gap-4 sm:gap-8 w-full'>
|
||||||
</div>
|
<div className='h-full w-full mt-0 ml-2 mb-16 flex items-center max-sm:grid max-sm:grid-row-start:auto max-sm:mb-6 max-sm:mt-10 max-sm:ml-0'>
|
||||||
<div className='items-center ml-auto mr-auto max-sm:mb-6 max-sm:w-full'>
|
<div className='w-[100px] max-sm:w-full max-sm:flex max-sm:justify-center'>
|
||||||
<LabeledInput
|
<Logo colorType='monochrome' logoType='submark' width={50} />
|
||||||
type='text'
|
|
||||||
label='Event Name'
|
|
||||||
placeholder={
|
|
||||||
props.type === 'create' ? 'New Event' : 'Event Name'
|
|
||||||
}
|
|
||||||
name='eventName'
|
|
||||||
variantSize='big'
|
|
||||||
value={title}
|
|
||||||
onChange={(e) => setTitle(e.target.value)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='w-0 sm:w-[50px]'></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className='grid grid-cols-4 gap-4 h-full w-full max-lg:grid-cols-2 max-sm:grid-cols-1'>
|
<div className='items-center ml-auto mr-auto max-sm:mb-6 max-sm:w-full'>
|
||||||
<div>
|
<LabeledInput
|
||||||
<TimePicker
|
type='text'
|
||||||
dateLabel='start Time'
|
label='Event Name'
|
||||||
timeLabel=' '
|
placeholder={
|
||||||
date={startDate}
|
props.type === 'create' ? 'New Event' : 'Event Name'
|
||||||
setDate={setStartDate}
|
}
|
||||||
time={startTime}
|
name='eventName'
|
||||||
setTime={setStartTime}
|
variantSize='big'
|
||||||
/>
|
value={title}
|
||||||
|
onChange={(e) => setTitle(e.target.value)}
|
||||||
|
data-cy='event-name-input'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='w-0 sm:w-[50px]'></div>
|
||||||
|
</div>
|
||||||
|
<div className='grid grid-cols-4 gap-4 h-full w-full max-lg:grid-cols-2 max-sm:grid-cols-1'>
|
||||||
|
<div>
|
||||||
|
<TimePicker
|
||||||
|
dateLabel='start Time'
|
||||||
|
timeLabel=' '
|
||||||
|
date={startDate}
|
||||||
|
setDate={setStartDate}
|
||||||
|
time={startTime}
|
||||||
|
setTime={setStartTime}
|
||||||
|
data-cy='event-start-time-picker'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<TimePicker
|
||||||
|
dateLabel='end Time'
|
||||||
|
timeLabel=' '
|
||||||
|
date={endDate}
|
||||||
|
setDate={setEndDate}
|
||||||
|
time={endTime}
|
||||||
|
setTime={setEndTime}
|
||||||
|
data-cy='event-end-time-picker'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='w-54'>
|
||||||
|
<LabeledInput
|
||||||
|
type='text'
|
||||||
|
label='Location'
|
||||||
|
placeholder='where is the event?'
|
||||||
|
name='eventLocation'
|
||||||
|
value={location}
|
||||||
|
onChange={(e) => setLocation(e.target.value)}
|
||||||
|
data-cy='event-location-input'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='flex flex-col gap-4'>
|
||||||
|
<div className='flex flex-row gap-2'>
|
||||||
|
<Label className='w-[70px]'>created:</Label>
|
||||||
|
<Label className='text-[var(--color-neutral-300)]'>
|
||||||
|
{createdAtDisplay}
|
||||||
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className='flex flex-row gap-2'>
|
||||||
<TimePicker
|
<Label className='w-[70px]'>updated:</Label>
|
||||||
dateLabel='end Time'
|
<p className='text-[var(--color-neutral-300)]'>
|
||||||
timeLabel=' '
|
{updatedAtDisplay}
|
||||||
date={endDate}
|
</p>
|
||||||
setDate={setEndDate}
|
|
||||||
time={endTime}
|
|
||||||
setTime={setEndTime}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div className='w-54'>
|
</div>
|
||||||
<LabeledInput
|
</div>
|
||||||
type='text'
|
<div className='h-full w-full grid grid-cols-2 gap-4 max-sm:grid-cols-1'>
|
||||||
label='Location'
|
<div className='h-full w-full grid grid-flow-row gap-4'>
|
||||||
placeholder='where is the event?'
|
<div className='h-full w-full'>
|
||||||
name='eventLocation'
|
|
||||||
value={location}
|
|
||||||
onChange={(e) => setLocation(e.target.value)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='flex flex-col gap-4'>
|
|
||||||
<div className='flex flex-row gap-2'>
|
<div className='flex flex-row gap-2'>
|
||||||
<Label className='w-[70px]'>created:</Label>
|
<Label>Organiser:</Label>
|
||||||
<Label className='text-[var(--color-neutral-300)]'>
|
|
||||||
{createdAtDisplay}
|
|
||||||
</Label>
|
|
||||||
</div>
|
|
||||||
<div className='flex flex-row gap-2'>
|
|
||||||
<Label className='w-[70px]'>updated:</Label>
|
|
||||||
<p className='text-[var(--color-neutral-300)]'>
|
<p className='text-[var(--color-neutral-300)]'>
|
||||||
{updatedAtDisplay}
|
{!isClient || isLoading
|
||||||
|
? 'Loading...'
|
||||||
|
: data?.data.user?.name || 'Unknown User'}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div className='h-full w-full grid grid-cols-2 gap-4 max-sm:grid-cols-1'>
|
|
||||||
<div className='h-full w-full grid grid-flow-row gap-4'>
|
|
||||||
<div className='h-full w-full'>
|
|
||||||
<div className='flex flex-row gap-2'>
|
|
||||||
<Label>Organiser:</Label>
|
|
||||||
<Label className='text-[var(--color-neutral-300)]'>
|
|
||||||
{organiserValue}
|
|
||||||
</Label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='h-full w-full'>
|
|
||||||
<LabeledInput
|
|
||||||
type='text'
|
|
||||||
label='Event Description'
|
|
||||||
placeholder='What is the event about?'
|
|
||||||
name='eventDescription'
|
|
||||||
variantSize='textarea'
|
|
||||||
value={description}
|
|
||||||
onChange={(e) => setDescription(e.target.value)}
|
|
||||||
></LabeledInput>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='h-full w-full'>
|
<div className='h-full w-full'>
|
||||||
<Label>Participants</Label>
|
<LabeledInput
|
||||||
<UserSearchInput
|
type='text'
|
||||||
selectedUsers={selectedParticipants}
|
label='Event Description'
|
||||||
addUserAction={(user) => {
|
placeholder='What is the event about?'
|
||||||
setSelectedParticipants((current) =>
|
name='eventDescription'
|
||||||
current.find((u) => u.id === user.id)
|
variantSize='textarea'
|
||||||
? current
|
value={description}
|
||||||
: [...current, user],
|
onChange={(e) => setDescription(e.target.value)}
|
||||||
);
|
data-cy='event-description-input'
|
||||||
}}
|
></LabeledInput>
|
||||||
removeUserAction={(user) => {
|
|
||||||
setSelectedParticipants((current) =>
|
|
||||||
current.filter((u) => u.id !== user.id),
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<DialogTrigger asChild>
|
|
||||||
<Button variant='primary'>Calendar</Button>
|
|
||||||
</DialogTrigger>
|
|
||||||
<div className='grid grid-cols-1 mt-3 sm:max-h-60 sm:grid-cols-2 sm:overflow-y-auto sm:mb-0'>
|
|
||||||
{selectedParticipants.map((user) => (
|
|
||||||
<ParticipantListEntry
|
|
||||||
key={user.id}
|
|
||||||
user={user}
|
|
||||||
status='PENDING'
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className='h-full w-full'>
|
||||||
<div className='flex flex-row gap-2 justify-end mt-4 mb-6'>
|
<Label>Participants</Label>
|
||||||
<div className='w-[20%] grid max-sm:w-[40%]'>
|
<UserSearchInput
|
||||||
<Button
|
selectedUsers={selectedParticipants}
|
||||||
type='button'
|
addUserAction={(user) => {
|
||||||
variant='secondary'
|
setSelectedParticipants((current) =>
|
||||||
onClick={() => {
|
current.find((u) => u.id === user.id)
|
||||||
router.back();
|
? current
|
||||||
console.log('user aborted - no change in database');
|
: [...current, user],
|
||||||
}}
|
);
|
||||||
>
|
}}
|
||||||
cancel
|
removeUserAction={(user) => {
|
||||||
</Button>
|
setSelectedParticipants((current) =>
|
||||||
</div>
|
current.filter((u) => u.id !== user.id),
|
||||||
<div className='w-[20%] grid max-sm:w-[40%]'>
|
);
|
||||||
<Button
|
}}
|
||||||
type='submit'
|
/>
|
||||||
variant='primary'
|
<DialogTrigger asChild>
|
||||||
disabled={status === 'pending'}
|
<Button variant='primary'>Calendar</Button>
|
||||||
>
|
</DialogTrigger>
|
||||||
{status === 'pending' ? 'Saving...' : 'save event'}
|
<div className='grid grid-cols-1 mt-3 sm:max-h-60 sm:grid-cols-2 sm:overflow-y-auto sm:mb-0'>
|
||||||
</Button>
|
{selectedParticipants.map((user) => (
|
||||||
|
<ParticipantListEntry
|
||||||
|
key={user.id}
|
||||||
|
user={user}
|
||||||
|
status='PENDING'
|
||||||
|
/>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{isSuccess && <p>Event created!</p>}
|
|
||||||
{error && <p className='text-red-500'>Error: {error.message}</p>}
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
|
||||||
<DialogContent className='sm:max-w-[750px]'>
|
<div className='flex flex-row gap-2 justify-end mt-4 mb-6'>
|
||||||
<DialogHeader>
|
<div className='w-[20%] grid max-sm:w-[40%]'>
|
||||||
<DialogTitle>Calendar</DialogTitle>
|
<Button
|
||||||
<DialogDescription>
|
type='button'
|
||||||
Calendar for selected participants
|
variant='secondary'
|
||||||
</DialogDescription>
|
onClick={() => {
|
||||||
</DialogHeader>
|
router.back();
|
||||||
<DialogFooter className='max-w-[calc(100svw-70px)]'>
|
console.log('user aborted - no change in database');
|
||||||
<Calendar
|
}}
|
||||||
userId={selectedParticipants.map((u) => u.id)}
|
>
|
||||||
additionalEvents={[
|
cancel
|
||||||
{
|
</Button>
|
||||||
id: 'temp-event',
|
</div>
|
||||||
title: title || 'New Event',
|
<div className='w-[20%] grid max-sm:w-[40%]'>
|
||||||
start: startDate ? new Date(startDate) : new Date(),
|
<Button
|
||||||
end: endDate ? new Date(endDate) : new Date(),
|
type='submit'
|
||||||
type: 'event',
|
variant='primary'
|
||||||
userId: 'create-event',
|
disabled={status === 'pending'}
|
||||||
colorOverride: '#ff9800',
|
data-cy='event-save-button'
|
||||||
},
|
>
|
||||||
]}
|
{status === 'pending' ? 'Saving...' : 'save event'}
|
||||||
height='600px'
|
</Button>
|
||||||
/>
|
</div>
|
||||||
</DialogFooter>
|
</div>
|
||||||
</DialogContent>
|
{isSuccess && <p>Event created!</p>}
|
||||||
</Dialog>
|
{error && <p className='text-red-500'>Error: {error.message}</p>}
|
||||||
</>
|
</div>
|
||||||
|
</form>
|
||||||
|
<DialogContent className='sm:max-w-[750px]'>
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Calendar</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
Calendar for selected participants
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<DialogFooter className='max-w-[calc(100svw-70px)]'>
|
||||||
|
<Calendar
|
||||||
|
userId={selectedParticipants.map((u) => u.id)}
|
||||||
|
additionalEvents={[
|
||||||
|
{
|
||||||
|
id: 'temp-event',
|
||||||
|
title: title || 'New Event',
|
||||||
|
start: startDate ? new Date(startDate) : new Date(),
|
||||||
|
end: endDate ? new Date(endDate) : new Date(),
|
||||||
|
type: 'event',
|
||||||
|
userId: 'create-event',
|
||||||
|
colorOverride: '#ff9800',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
height='600px'
|
||||||
|
/>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,10 @@ export default function Header({
|
||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<div className='w-full grid grid-rows-[50px_1fr] h-screen'>
|
<div className='w-full grid grid-rows-[50px_1fr] h-screen'>
|
||||||
<header className='border-b-1 grid-cols-[1fr_3fr_1fr] grid items-center px-2 shadow-md'>
|
<header
|
||||||
|
className='border-b-1 grid-cols-[1fr_3fr_1fr] grid items-center px-2 shadow-md'
|
||||||
|
data-cy='header'
|
||||||
|
>
|
||||||
<span className='flex justify-start'>
|
<span className='flex justify-start'>
|
||||||
<SidebarTrigger variant='outline_primary' size='icon' />
|
<SidebarTrigger variant='outline_primary' size='icon' />
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -20,6 +20,7 @@ export default function TimePicker({
|
||||||
setDate,
|
setDate,
|
||||||
time,
|
time,
|
||||||
setTime,
|
setTime,
|
||||||
|
...props
|
||||||
}: {
|
}: {
|
||||||
dateLabel?: string;
|
dateLabel?: string;
|
||||||
timeLabel?: string;
|
timeLabel?: string;
|
||||||
|
@ -27,11 +28,11 @@ export default function TimePicker({
|
||||||
setDate?: (date: Date | undefined) => void;
|
setDate?: (date: Date | undefined) => void;
|
||||||
time?: string;
|
time?: string;
|
||||||
setTime?: (time: string) => void;
|
setTime?: (time: string) => void;
|
||||||
}) {
|
} & React.HTMLAttributes<HTMLDivElement>) {
|
||||||
const [open, setOpen] = React.useState(false);
|
const [open, setOpen] = React.useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex gap-4'>
|
<div className='flex gap-4' {...props}>
|
||||||
<div className='flex flex-col gap-3'>
|
<div className='flex flex-col gap-3'>
|
||||||
<Label htmlFor='date' className='px-1'>
|
<Label htmlFor='date' className='px-1'>
|
||||||
{dateLabel}
|
{dateLabel}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue