Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,9 @@
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB (Preview) and CockroachDB (Preview).
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings

DATABASE_URL="postgres://xx:xxxxxxx@xxxxx/xxxxx"
DATABASE_URL="postgres://xx:xxxxxxx@xxxxx/xxxxx"

APPWRITE_PROJECT_ID="projectid"
APPWRITE_DATABASE_ID="databaseid"
APPWRITE_COLLECTION_ID="collectionid"
APPWRITE_READ_TOKEN="standard"
42 changes: 42 additions & 0 deletions actions/fetchTemplates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
'use server';
import { Client, Databases, Models, Query } from 'node-appwrite';
import { TemplateInformations } from '../config/templates';

const APPWRITE_PROJECT_ID = process.env.APPWRITE_PROJECT_ID!;
const APPWRITE_DATABASE_ID = process.env.APPWRITE_DATABASE_ID!;
const APPWRITE_COLLECTION_ID = process.env.APPWRITE_COLLECTION_ID!;
const APPWRITE_READ_TOKEN = process.env.APPWRITE_READ_TOKEN!;

const client = new Client()
.setKey(APPWRITE_READ_TOKEN)
.setEndpoint('https://cloud.appwrite.io/v1')
.setProject(APPWRITE_PROJECT_ID);

const databases = new Databases(client);

export default async function fetchTemplates(): Promise<
TemplateInformations[]
> {
const promise = await databases.listDocuments<
Models.Document & Omit<TemplateInformations, 'eventId'> & { show: boolean }
>(APPWRITE_DATABASE_ID, APPWRITE_COLLECTION_ID, [Query.equal('show', true)]);
return promise.documents.map(
({
eventName,
referenceImage,
instructions,
showPreview,
demoMode,
injectCode,
$id,
}) => ({
eventId: $id,
eventName,
referenceImage,
instructions,
showPreview,
demoMode,
injectCode,
})
);
}
8 changes: 8 additions & 0 deletions app/compete/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use client';
import StartForm from '../../components/forms/StartForm';
import { useFetchTemplates } from '../../hooks/useFetchTemplates';

export default function Page() {
const { templates = [] } = useFetchTemplates();
return <StartForm templates={templates}></StartForm>;
}
93 changes: 11 additions & 82 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,83 +1,12 @@
'use client';

import { useForm } from 'react-hook-form';
import { useRouter } from 'next/navigation';
import { useEntryStore } from '../hooks/useEntryStore';
import React, { useEffect, useState } from 'react';
import { TemplateName, templatesDictionary } from "../config/templates";
import Image from 'next/image';

import styles from '../styles/register.module.scss';

export default function Page() {
const router = useRouter();
const [selectedTemplate, setSelectedTemplate] = useState<TemplateName>(
TemplateName.CITD
);
const { entry, updateFullName, updateId, updateIsLoading, updateTemplate } =
useEntryStore();
const { register, handleSubmit, formState } = useForm({
defaultValues: { fullName: entry?.fullName, templateName: entry?.template },
});

const onSubmit = async (data: { [x: string]: any }) => {
updateIsLoading(true);
updateFullName(data.fullName);
updateTemplate(data.templateName);

// TODO : Create user in DB

updateId(0);
updateIsLoading(false);

router.push('/editor');
};

useEffect(() => {
if (entry?.id) {
router.push('/editor');
}
}, [router, entry?.id]);

return (
<>
<form onSubmit={handleSubmit(onSubmit)} className={styles.registerForm}>
<h1>Welcome!</h1>
<h3>Please state your name 👇🏼</h3>
<input
type='text'
placeholder='Name'
{...register('fullName', { required: true, max: 80, min: 5 })}
className={formState.errors.fullName ? styles.isWizz : ''}
/>

<label htmlFor='templateSelect'>Select a template:</label>
<select
id='templateSelect'
value={selectedTemplate}
{...register('templateName', {
required: true,
onChange: (e) => setSelectedTemplate(e.target.value),
})}
>
{Object.keys(TemplateName).map((template) => (
<option
key={template}
value={TemplateName[template as keyof typeof TemplateName]}
>
{template}
</option>
))}
</select>
<Image
priority
src={templatesDictionary[selectedTemplate].referenceImage}
alt='Image template reference'
width={200}
height={200}
/>
<input type='submit' className='button' />
</form>
</>
);
import StartForm from '../components/forms/StartForm';
import { TemplateInformations, templatesDictionary } from '../config/templates';

export default async function Page() {
const templates: TemplateInformations[] = Object.entries(
templatesDictionary
).map(([key, value]) => ({
...value,
eventName: key,
}));
return <StartForm templates={templates}></StartForm>;
}
14 changes: 14 additions & 0 deletions components/forms/CompetitionStartingForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { TemplateInformations } from '../../config/templates';

import { useFetchTemplates } from '../../hooks/useFetchTemplates';
import StartForm from './StartForm';

export default function CompetitionStartingForm({
templates: newTemplates,
}: {
templates: TemplateInformations[];
}) {
const { templates = newTemplates } = useFetchTemplates();

return <StartForm templates={templates} />;
}
94 changes: 94 additions & 0 deletions components/forms/StartForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
'use client';

import Image from 'next/image';
import { useRouter } from 'next/navigation';
import { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { TemplateInformations } from '../../config/templates';
import { useEntryStore } from '../../hooks/useEntryStore';

import styles from '../../styles/register.module.scss';

export default function StartForm({
templates,
}: {
templates: TemplateInformations[];
}) {
const router = useRouter();
const [selectedTemplateIndex, setSelectedTemplateIndex] = useState<number>(0);
const { entry, updateFullName, updateId, updateIsLoading, updateTemplate } =
useEntryStore();
const { register, handleSubmit, formState } = useForm({
defaultValues: { fullName: entry?.fullName, templateName: entry?.template },
});
useEffect(() => {
if (entry?.id) {
router.push('/editor');
}
}, [router, entry?.id]);

const onSubmit = async (data: { [x: string]: any }) => {
updateIsLoading(true);
updateFullName(data.fullName);
const selectedTemplate = templates.at(data.templateName);
if (selectedTemplate) {
updateTemplate(selectedTemplate);
} else {
throw new Error('No template found');
}

// TODO : Create user in DB

updateId(0);
updateIsLoading(false);

router.push('/editor');
};

return (
<>
<form onSubmit={handleSubmit(onSubmit)} className={styles.registerForm}>
<h1>Welcome!</h1>
<h3>Please state your name 👇🏼</h3>
<input
type='text'
placeholder='Name'
{...register('fullName', { required: true, max: 80, min: 5 })}
className={formState.errors.fullName ? styles.isWizz : ''}
/>

{templates.length === 0 ? (
<>Please wait...</>
) : (
<>
<label htmlFor='templateSelect'>Select a template:</label>
<select
id='templateSelect'
value={selectedTemplateIndex}
{...register('templateName', {
required: true,
onChange: (e) => setSelectedTemplateIndex(e.target.value),
})}
>
{templates.map((value, index) => (
<option key={value.eventId} value={index}>
{value.eventName}
</option>
))}
</select>
{templates[selectedTemplateIndex] && (
<Image
priority
src={templates[selectedTemplateIndex].referenceImage}
alt='Image template reference'
width={200}
height={200}
/>
)}
<input type='submit' className='button' />
</>
)}
</form>
</>
);
}
2 changes: 1 addition & 1 deletion config/templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {CityTemplate} from "./city.template";
import {CitdTemplate} from "./citd.template";

export interface TemplateInformations {
eventId: number;
eventId: number | string;
eventName: string;
referenceImage: string;
instructions: string;
Expand Down
8 changes: 4 additions & 4 deletions hooks/useEntryStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ interface EntryStore {
entry: Entry | null;
updateId: (id: number) => void;
updateFullName: (fullName: string) => void;
updateTemplate: (reference: TemplateNameList) => void;
updateTemplate: (template: TemplateInformations) => void;
updateHtml: (html: string) => void;
updateIsSubmitted: (submitted: boolean) => void;
updateIsLoading: (isLoading: boolean) => void;
Expand Down Expand Up @@ -49,11 +49,11 @@ export const useEntryStore = create<EntryStore>()(
},
}));
},
updateTemplate: (templateName: TemplateNameList) => {
updateTemplate: (template: TemplateInformations) => {
set((state) => ({
entry: {
...state.entry,
template: templatesDictionary[templateName],
template: template,
},
}));
},
Expand Down Expand Up @@ -86,4 +86,4 @@ export const useEntryStore = create<EntryStore>()(
skipHydration: true,
}
)
);
);
17 changes: 17 additions & 0 deletions hooks/useFetchTemplates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use client';
import useSWR from 'swr';
import fetchTemplates from '../actions/fetchTemplates';

export function useFetchTemplates() {
const { data: templates } = useSWR(
'templates',
async () => {
return await fetchTemplates();
},
{
refreshInterval: 2000,
}
);

return { templates };
}
9 changes: 9 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'cloud.appwrite.io',
pathname: '/v1/storage/buckets/**',
},
],
},
};

module.exports = nextConfig;
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
},
"dependencies": {
"ace-builds": "1.32.7",
"appwrite": "14.0.1",
"classnames": "2.5.1",
"framer-motion": "11.0.8",
"next": "14.1.2",
"node-appwrite": "^14.1.0",
"query-string": "7.1.1",
"react": "18.2.0",
"react-ace": "10.1.0",
Expand Down
Loading