Skip to content

Commit

Permalink
Add create event (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
frankbille authored Nov 16, 2024
1 parent bab4196 commit de87091
Show file tree
Hide file tree
Showing 18 changed files with 261 additions and 52 deletions.
53 changes: 53 additions & 0 deletions src/admin/event/new/AdminCreateEvent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {RouterDialog, RouterDialogAction} from "../../../components/RouterDialog.tsx";
import {t, Trans} from "@lingui/macro";
import {useActionData} from "react-router-dom";
import {OptionalErrorResponseBody} from "../../../utils/responses.ts";
import {translateErrorCode} from "../../../gql";
import {JidCodeInput} from "../../../components/JidCodeInput.tsx";
import {useState} from "react";

export const AdminCreateEvent = () => {
const [jidCode, setJidCode] = useState<string>("");

const actionData = useActionData() as OptionalErrorResponseBody;

const error = actionData?.errorCode
? translateErrorCode(actionData.errorCode)
: actionData?.error;

const dialogActions: RouterDialogAction[] = [{
label: <Trans>Cancel</Trans>,
type: "button",
callback: callback => callback.cancel(),
}, {
label: <Trans>Create</Trans>,
type: "submit",
name: "createButton",
classNames: "btn-primary",
}];

return (
<RouterDialog title={<Trans>Add event</Trans>} actions={dialogActions}>
<label className="form-control w-full">
<JidCodeInput
style={"form"}
name="code"
onValidJidCode={() => {
}} jidCode={jidCode}
setJidCode={setJidCode}/>
</label>
<label className="form-control w-full mt-4">
<input type="number"
placeholder={t`Location name`}
required={true}
defaultValue={new Date().getFullYear()}
autoComplete="off"
name="year"
className={`input input-bordered w-full`}/>
</label>
{error && <div className="label">
<span className="label-text text-error">{error}</span>
</div>}
</RouterDialog>
)
}
5 changes: 5 additions & 0 deletions src/admin/event/new/CreateEvent.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mutation CreateEvent($input: CreateEventInput!) {
createEvent(input: $input) {
id
}
}
34 changes: 34 additions & 0 deletions src/admin/event/new/adminCreateEventAction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {ActionFunctionArgs, replace} from "react-router-dom";
import {client, CreateEventDocument, hasErrorCode, ServerErrorCode} from "../../../gql";
import {badRequest} from "../../../utils/responses.ts";

export const adminCreateEventAction = async ({params, request}: ActionFunctionArgs) => {
const formData = await request.formData();

if (formData.has("createButton") && formData.get("code") && formData.get("year")) {
const locationId = params.locationId as string;
const code = formData.get("code") as string;
const year = +(formData.get("year") as string);

const result = await client.mutation(CreateEventDocument, {
input: {
locationId,
code,
year,
active: false,
}
});

if (result.error) {
if (hasErrorCode(result.error, ServerErrorCode.EVENT_CODE_AND_YEAR_NOT_AVAILABLE)) {
return badRequest({errorCode: ServerErrorCode.EVENT_CODE_AND_YEAR_NOT_AVAILABLE});
} else {
return badRequest({error: result.error.message});
}
}

return replace(`/admin/locations/$\{params.locationId}/events/${result.data?.createEvent?.id}`);
}

return replace(`/admin/locations/${params.locationId}`);
}
2 changes: 2 additions & 0 deletions src/admin/event/new/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./adminCreateEventAction.ts";
export * from "./AdminCreateEvent.tsx";
39 changes: 27 additions & 12 deletions src/admin/location/AdminLocation.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {useEffect} from "react";
import {Trans} from "@lingui/macro";
import {useLoaderData} from "react-router-dom";
import {t, Trans} from "@lingui/macro";
import {Link, Outlet, useLoaderData} from "react-router-dom";
import {PlusIcon} from "@heroicons/react/24/solid";

import {Dashboard} from "../../components/Dashboard.tsx";
import {GetAdminLocationQuery} from "../../gql";
Expand All @@ -19,15 +20,29 @@ export const AdminLocation = () => {
}, [setNavigationCenter, setNavigationButtons, loaderData]);

return (
<Dashboard columns={3} widgets={[{
key: "events",
title: <Trans>Events</Trans>,
content: <AdminLocationEventTable getAdminLocationEventsFragment={loaderData.location!}/>,
span: 2,
}, {
key: "owners",
title: <Trans>Owners</Trans>,
content: <AdminLocationOwnerTable getAdminLocationOwnerFragment={loaderData.location!}/>,
}]}/>
<>
<Dashboard columns={3} widgets={[{
key: "events",
title: <Trans>Events</Trans>,
content: <AdminLocationEventTable locationId={loaderData.location!.id}
getAdminLocationEventsFragment={loaderData.location!}/>,
span: 2,
}, {
key: "owners",
title: <Trans>Owners</Trans>,
content: <AdminLocationOwnerTable getAdminLocationOwnerFragment={loaderData.location!}/>,
}]}/>

<div className="toast mb-14">
<div className="tooltip tooltip-left" data-tip={t`Add event`}>
<Link to={`/admin/locations/${loaderData.location?.id}/events/new`}
className="btn btn-primary btn-circle">
<PlusIcon className="size-7"/>
</Link>
</div>
</div>

<Outlet/>
</>
)
}
5 changes: 3 additions & 2 deletions src/admin/location/AdminLocationEventTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import {Link} from "react-router-dom";
import {RocketLaunchIcon, StopIcon} from "@heroicons/react/16/solid";

type AdminLocationEventTableProps = {
locationId: string
getAdminLocationEventsFragment: FragmentType<typeof GetAdminLocationEventsFragmentDoc>
}

export const AdminLocationEventTable = ({getAdminLocationEventsFragment}: AdminLocationEventTableProps) => {
export const AdminLocationEventTable = ({locationId, getAdminLocationEventsFragment}: AdminLocationEventTableProps) => {
const getAdminLocationEvents = useFragment(GetAdminLocationEventsFragmentDoc, getAdminLocationEventsFragment);

const events = getAdminLocationEvents.events!;
Expand All @@ -21,7 +22,7 @@ export const AdminLocationEventTable = ({getAdminLocationEventsFragment}: AdminL
key: "year",
header: <Trans>Year</Trans>,
getValue: event => (
<Link to={`/admin/event/${event.id}`} className="link">{event.year}</Link>
<Link to={`/admin/locations/${locationId}/events/${event.id}`} className="link">{event.year}</Link>
),
sort: numberSort(event => event.year),
sortAscendingDefault: false,
Expand Down
2 changes: 1 addition & 1 deletion src/admin/location/AdminLocationTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const AdminLocationTable = ({getAdminLocationsFragment}: AdminLocationTab
header: <Trans>Latest Event</Trans>,
getValue: location => (
location.latestEvent &&
<Link className="link" to={`/admin/event/${location.latestEvent.id}`}>{location.latestEvent.year}</Link>
<Link className="link" to={`/admin/locations/${location.id}/events/${location.latestEvent.id}`}>{location.latestEvent.year}</Link>
),
sort: numberSort(location => location.latestEvent ? location.latestEvent.year : 0),
sortAscendingDefault: false,
Expand Down
18 changes: 16 additions & 2 deletions src/components/JidCodeInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ type JidCodeInputProps = {
onValidJidCode: (validJidCode: string | null) => void
jidCode: string
setJidCode: (jidCode: string) => void
style?: "form" | "large"
name?: string
}

export const jidCodeRegex = /[1-7]([A-Z]{2})[0-9]{2}[A-Z]/
Expand All @@ -28,7 +30,7 @@ const maskitoOptions: MaskitoOptions = {
],
}

export const JidCodeInput = ({onValidJidCode, jidCode, setJidCode}: JidCodeInputProps) => {
export const JidCodeInput = ({onValidJidCode, jidCode, setJidCode, style, name}: JidCodeInputProps) => {

const inputRef = useMaskito({
options: maskitoOptions,
Expand All @@ -48,16 +50,28 @@ export const JidCodeInput = ({onValidJidCode, jidCode, setJidCode}: JidCodeInput
}
}

const styleClasses = () => {
switch (style) {
case "form":
return "";
case "large":
return `input-lg tracking-widest font-mono text-center${validJidCode ? ' input-success' : ''}`;
default:
return "";
}
}

return (
<input
type="text"
ref={inputRef}
pattern={jidCodeRegex.source}
required={true}
value={jidCode}
name={name}
placeholder={t`Add Code`}
onInput={onValueUpdated}
className={`input input-bordered input-lg tracking-widest font-mono text-center ${validJidCode ? 'input-success' : ''}`}
className={`input input-bordered ${styleClasses()}`}
/>
);
}
2 changes: 1 addition & 1 deletion src/event/AuthenticatedButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const AuthenticatedButtons = ({data, reloadEvent}: AuthenticatedButtonsPr

if (isAdminAuthenticated(data)) {
dropdownLinks.push(
<Link to={`/admin/event/${data.event?.id}`}>
<Link to={`/admin/locations/${data.event?.location.id}/events/${data.event?.id}`}>
<Trans>Admin</Trans>
</Link>
);
Expand Down
1 change: 1 addition & 0 deletions src/event/GetEvent.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ query GetEvent($code: String!) {
event(code: $code) {
id
location {
id
name
owners {
id
Expand Down
9 changes: 7 additions & 2 deletions src/gql/__autogenerated/gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/
const documents = {
"query Admin {\n authenticatedAdmin {\n id\n name\n }\n ...GetFooter\n}": types.AdminDocument,
"query GetAdminEvent($eventId: ID!) {\n eventById(eventId: $eventId) {\n id\n code {\n value\n }\n year\n jidCodeStats {\n count\n uniqueCount\n uniqueCountries\n }\n location {\n id\n name\n }\n }\n}": types.GetAdminEventDocument,
"mutation CreateEvent($input: CreateEventInput!) {\n createEvent(input: $input) {\n id\n }\n}": types.CreateEventDocument,
"query GetAdminLocation($locationId: ID!) {\n location(locationId: $locationId) {\n id\n name\n ...GetAdminLocationEvents\n ...GetAdminLocationOwners\n }\n}": types.GetAdminLocationDocument,
"fragment GetAdminLocationEvents on Location {\n events {\n id\n code {\n value\n }\n year\n active\n jidCodeStats {\n count\n uniqueCount\n uniqueCountryCount\n }\n participants {\n id\n }\n }\n}": types.GetAdminLocationEventsFragmentDoc,
"fragment GetAdminLocationOwners on Location {\n owners {\n id\n name\n }\n}": types.GetAdminLocationOwnersFragmentDoc,
Expand All @@ -28,7 +29,7 @@ const documents = {
"mutation CreateAdmin($input: CreateAdmin!) {\n createAdmin(input: $input) {\n id\n }\n}": types.CreateAdminDocument,
"fragment GetFooter on Query {\n serverVersion\n}": types.GetFooterFragmentDoc,
"subscription EventSubscription($eventId: ID!) {\n eventUpdated(eventId: $eventId)\n}": types.EventSubscriptionDocument,
"query GetEvent($code: String!) {\n authenticatedParticipant {\n id\n name\n event {\n id\n }\n }\n authenticatedAdmin {\n id\n }\n event(code: $code) {\n id\n location {\n name\n owners {\n id\n }\n }\n code {\n value\n }\n year\n jidCodeStats {\n count\n uniqueCount\n uniqueCountryCount\n }\n ...Countries\n ...Participants\n ...StatBar\n }\n ...GetFooter\n}": types.GetEventDocument,
"query GetEvent($code: String!) {\n authenticatedParticipant {\n id\n name\n event {\n id\n }\n }\n authenticatedAdmin {\n id\n }\n event(code: $code) {\n id\n location {\n id\n name\n owners {\n id\n }\n }\n code {\n value\n }\n year\n jidCodeStats {\n count\n uniqueCount\n uniqueCountryCount\n }\n ...Countries\n ...Participants\n ...StatBar\n }\n ...GetFooter\n}": types.GetEventDocument,
"mutation RegisterJidCode($input: RegisterFoundJidCode!) {\n registerFoundJidCode(input: $input) {\n id\n }\n}": types.RegisterJidCodeDocument,
"fragment Countries on Event {\n jidCodeStats {\n countryStats {\n country\n uniqueCount\n }\n }\n}": types.CountriesFragmentDoc,
"mutation AuthenticateParticipant($eventId: ID!, $name: String!, $pinCode: String!) {\n authenticateParticipant(eventId: $eventId, name: $name, pinCode: $pinCode)\n}": types.AuthenticateParticipantDocument,
Expand Down Expand Up @@ -61,6 +62,10 @@ export function graphql(source: "query Admin {\n authenticatedAdmin {\n id\n
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "query GetAdminEvent($eventId: ID!) {\n eventById(eventId: $eventId) {\n id\n code {\n value\n }\n year\n jidCodeStats {\n count\n uniqueCount\n uniqueCountries\n }\n location {\n id\n name\n }\n }\n}"): (typeof documents)["query GetAdminEvent($eventId: ID!) {\n eventById(eventId: $eventId) {\n id\n code {\n value\n }\n year\n jidCodeStats {\n count\n uniqueCount\n uniqueCountries\n }\n location {\n id\n name\n }\n }\n}"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "mutation CreateEvent($input: CreateEventInput!) {\n createEvent(input: $input) {\n id\n }\n}"): (typeof documents)["mutation CreateEvent($input: CreateEventInput!) {\n createEvent(input: $input) {\n id\n }\n}"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
Expand Down Expand Up @@ -112,7 +117,7 @@ export function graphql(source: "subscription EventSubscription($eventId: ID!) {
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "query GetEvent($code: String!) {\n authenticatedParticipant {\n id\n name\n event {\n id\n }\n }\n authenticatedAdmin {\n id\n }\n event(code: $code) {\n id\n location {\n name\n owners {\n id\n }\n }\n code {\n value\n }\n year\n jidCodeStats {\n count\n uniqueCount\n uniqueCountryCount\n }\n ...Countries\n ...Participants\n ...StatBar\n }\n ...GetFooter\n}"): (typeof documents)["query GetEvent($code: String!) {\n authenticatedParticipant {\n id\n name\n event {\n id\n }\n }\n authenticatedAdmin {\n id\n }\n event(code: $code) {\n id\n location {\n name\n owners {\n id\n }\n }\n code {\n value\n }\n year\n jidCodeStats {\n count\n uniqueCount\n uniqueCountryCount\n }\n ...Countries\n ...Participants\n ...StatBar\n }\n ...GetFooter\n}"];
export function graphql(source: "query GetEvent($code: String!) {\n authenticatedParticipant {\n id\n name\n event {\n id\n }\n }\n authenticatedAdmin {\n id\n }\n event(code: $code) {\n id\n location {\n id\n name\n owners {\n id\n }\n }\n code {\n value\n }\n year\n jidCodeStats {\n count\n uniqueCount\n uniqueCountryCount\n }\n ...Countries\n ...Participants\n ...StatBar\n }\n ...GetFooter\n}"): (typeof documents)["query GetEvent($code: String!) {\n authenticatedParticipant {\n id\n name\n event {\n id\n }\n }\n authenticatedAdmin {\n id\n }\n event(code: $code) {\n id\n location {\n id\n name\n owners {\n id\n }\n }\n code {\n value\n }\n year\n jidCodeStats {\n count\n uniqueCount\n uniqueCountryCount\n }\n ...Countries\n ...Participants\n ...StatBar\n }\n ...GetFooter\n}"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
Expand Down
Loading

0 comments on commit de87091

Please sign in to comment.