It's finally over
This commit is contained in:
parent
1a1fedfa08
commit
c553f9bfff
28 changed files with 1197 additions and 60 deletions
|
@ -0,0 +1,31 @@
|
||||||
|
'use client';
|
||||||
|
import React from "react";
|
||||||
|
import { useFormik } from "formik";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
|
export function Form({contentID}:{contentID:string}) {
|
||||||
|
const router = useRouter();
|
||||||
|
const formik = useFormik({
|
||||||
|
initialValues: {},
|
||||||
|
onSubmit: async (values) => {
|
||||||
|
const submitRequest = await fetch(`/jams/api/content/${contentID}`, {
|
||||||
|
method: "DELETE"
|
||||||
|
});
|
||||||
|
|
||||||
|
if (submitRequest.ok) {
|
||||||
|
router.push(`/jams/`);
|
||||||
|
} else {
|
||||||
|
formik.setSubmitting(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={formik.handleSubmit}>
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="submit">Are you sure?</label></p>
|
||||||
|
<input id="submit" name="submit" type="submit" value="Delete" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
67
src/app/jams/(manip)/delete/content/[contentid]/page.tsx
Normal file
67
src/app/jams/(manip)/delete/content/[contentid]/page.tsx
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
|
||||||
|
import { Conditional, ConditionalNull } from "@/components/utility/Conditional";
|
||||||
|
import { MainLayout } from "@/layout/MainLayout/MainLayout";
|
||||||
|
import { db } from "@/lib/mastoauth/kysely";
|
||||||
|
import { JSONContentTable, JSONJamTable } from "@/lib/mastoauth/realtypes";
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
import { notFound, redirect } from "next/navigation";
|
||||||
|
import { Form } from "./components/form";
|
||||||
|
|
||||||
|
export default async function Home({
|
||||||
|
params
|
||||||
|
}: {
|
||||||
|
params: {
|
||||||
|
contentid: string
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
const cookieStore = cookies();
|
||||||
|
const token = cookieStore.get('token')?.value;
|
||||||
|
let existingUser;
|
||||||
|
if (token != null) {
|
||||||
|
let existingToken = await db
|
||||||
|
.selectFrom('tokens')
|
||||||
|
.where('tokens.id', '=', token)
|
||||||
|
.select('owner')
|
||||||
|
.executeTakeFirst();
|
||||||
|
|
||||||
|
if (existingToken != null) {
|
||||||
|
existingUser = await db
|
||||||
|
.selectFrom('users')
|
||||||
|
.where('users.id', '=', existingToken.owner)
|
||||||
|
.selectAll()
|
||||||
|
.executeTakeFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existingUser == null) return redirect("/jams/");
|
||||||
|
|
||||||
|
const contentid = params.contentid;
|
||||||
|
|
||||||
|
if (contentid == null) return notFound();
|
||||||
|
|
||||||
|
// It's a JSONJamTable. I don't know why TS hates `number` => `string` conversion.
|
||||||
|
let editingContent = await db
|
||||||
|
.selectFrom('content')
|
||||||
|
.where('content.id', '=', contentid)
|
||||||
|
.selectAll()
|
||||||
|
.executeTakeFirst() as unknown as JSONContentTable;
|
||||||
|
|
||||||
|
if (editingContent == null) return notFound();
|
||||||
|
|
||||||
|
if (!existingUser.admin && editingContent.author_id != existingUser.id) return (
|
||||||
|
<MainLayout currentPage="/jams/" title="Delete Submission" subtitle="Jams" backButton>
|
||||||
|
<h1>Can't delete this submission</h1>
|
||||||
|
<p>You do not own this submission</p>
|
||||||
|
</MainLayout>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MainLayout currentPage="/jams/" title="Delete Submission" subtitle="Jams" backButton>
|
||||||
|
<p>Deleting <a href={`/jams/content/${editingContent.id}`}>{editingContent.name}</a></p>
|
||||||
|
<ConditionalNull condition={existingUser != null}>
|
||||||
|
<p><small>Logged in as <b>{existingUser?.username}@{existingUser?.instance}</b></small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
<Form contentID={editingContent.id} />
|
||||||
|
</MainLayout>
|
||||||
|
)
|
||||||
|
}
|
31
src/app/jams/(manip)/delete/jam/[jamid]/components/form.tsx
Normal file
31
src/app/jams/(manip)/delete/jam/[jamid]/components/form.tsx
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
'use client';
|
||||||
|
import React from "react";
|
||||||
|
import { useFormik } from "formik";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
|
export function Form({jamID}:{jamID:string}) {
|
||||||
|
const router = useRouter();
|
||||||
|
const formik = useFormik({
|
||||||
|
initialValues: {},
|
||||||
|
onSubmit: async (values) => {
|
||||||
|
const submitRequest = await fetch(`/jams/api/jams/${jamID}`, {
|
||||||
|
method: "DELETE"
|
||||||
|
});
|
||||||
|
|
||||||
|
if (submitRequest.ok) {
|
||||||
|
router.push(`/jams/`);
|
||||||
|
} else {
|
||||||
|
formik.setSubmitting(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={formik.handleSubmit}>
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="submit">Are you sure?</label></p>
|
||||||
|
<input id="submit" name="submit" type="submit" value="Delete" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
67
src/app/jams/(manip)/delete/jam/[jamid]/page.tsx
Normal file
67
src/app/jams/(manip)/delete/jam/[jamid]/page.tsx
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
|
||||||
|
import { Conditional, ConditionalNull } from "@/components/utility/Conditional";
|
||||||
|
import { MainLayout } from "@/layout/MainLayout/MainLayout";
|
||||||
|
import { db } from "@/lib/mastoauth/kysely";
|
||||||
|
import { JSONContentTable, JSONJamTable } from "@/lib/mastoauth/realtypes";
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
import { notFound, redirect } from "next/navigation";
|
||||||
|
import { Form } from "./components/form";
|
||||||
|
|
||||||
|
export default async function Home({
|
||||||
|
params
|
||||||
|
}: {
|
||||||
|
params: {
|
||||||
|
jamid: string
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
const cookieStore = cookies();
|
||||||
|
const token = cookieStore.get('token')?.value;
|
||||||
|
let existingUser;
|
||||||
|
if (token != null) {
|
||||||
|
let existingToken = await db
|
||||||
|
.selectFrom('tokens')
|
||||||
|
.where('tokens.id', '=', token)
|
||||||
|
.select('owner')
|
||||||
|
.executeTakeFirst();
|
||||||
|
|
||||||
|
if (existingToken != null) {
|
||||||
|
existingUser = await db
|
||||||
|
.selectFrom('users')
|
||||||
|
.where('users.id', '=', existingToken.owner)
|
||||||
|
.selectAll()
|
||||||
|
.executeTakeFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existingUser == null) return redirect("/jams/");
|
||||||
|
|
||||||
|
const jamid = params.jamid;
|
||||||
|
|
||||||
|
if (jamid == null) return notFound();
|
||||||
|
|
||||||
|
// It's a JSONJamTable. I don't know why TS hates `number` => `string` conversion.
|
||||||
|
let editingJam = await db
|
||||||
|
.selectFrom('jams')
|
||||||
|
.where('jams.id', '=', jamid)
|
||||||
|
.selectAll()
|
||||||
|
.executeTakeFirst() as unknown as JSONJamTable;
|
||||||
|
|
||||||
|
if (editingJam == null) return notFound();
|
||||||
|
|
||||||
|
if (!existingUser.admin && editingJam.author_id != existingUser.id) return (
|
||||||
|
<MainLayout currentPage="/jams/" title="Delete Jam" subtitle="Jams" backButton>
|
||||||
|
<h1>Can't delete this Jam</h1>
|
||||||
|
<p>You do not own this Jam</p>
|
||||||
|
</MainLayout>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MainLayout currentPage="/jams/" title="Delete Jam" subtitle="Jams" backButton>
|
||||||
|
<p>Deleting <a href={`/jams/content/${editingJam.id}`}>{editingJam.name}</a></p>
|
||||||
|
<ConditionalNull condition={existingUser != null}>
|
||||||
|
<p><small>Logged in as <b>{existingUser?.username}@{existingUser?.instance}</b></small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
<Form jamID={editingJam.id} />
|
||||||
|
</MainLayout>
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
'use client';
|
||||||
|
import React from "react";
|
||||||
|
import { useFormik } from "formik";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
|
export function Form({judgementID, contentID}:{judgementID:string, contentID:string}) {
|
||||||
|
const router = useRouter();
|
||||||
|
const formik = useFormik({
|
||||||
|
initialValues: {},
|
||||||
|
onSubmit: async (values) => {
|
||||||
|
const submitRequest = await fetch(`/jams/api/content/${contentID}/judgements/${judgementID}`, {
|
||||||
|
method: "DELETE"
|
||||||
|
});
|
||||||
|
|
||||||
|
if (submitRequest.ok) {
|
||||||
|
router.push(`/jams/`);
|
||||||
|
} else {
|
||||||
|
formik.setSubmitting(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={formik.handleSubmit}>
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="submit">Are you sure?</label></p>
|
||||||
|
<input id="submit" name="submit" type="submit" value="Delete" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
67
src/app/jams/(manip)/delete/judgement/[judgementid]/page.tsx
Normal file
67
src/app/jams/(manip)/delete/judgement/[judgementid]/page.tsx
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
|
||||||
|
import { Conditional, ConditionalNull } from "@/components/utility/Conditional";
|
||||||
|
import { MainLayout } from "@/layout/MainLayout/MainLayout";
|
||||||
|
import { db } from "@/lib/mastoauth/kysely";
|
||||||
|
import { JSONContentTable, JSONJamTable, JSONJudgementTable } from "@/lib/mastoauth/realtypes";
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
import { notFound, redirect } from "next/navigation";
|
||||||
|
import { Form } from "./components/form";
|
||||||
|
|
||||||
|
export default async function Home({
|
||||||
|
params
|
||||||
|
}: {
|
||||||
|
params: {
|
||||||
|
judgementid: string
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
const cookieStore = cookies();
|
||||||
|
const token = cookieStore.get('token')?.value;
|
||||||
|
let existingUser;
|
||||||
|
if (token != null) {
|
||||||
|
let existingToken = await db
|
||||||
|
.selectFrom('tokens')
|
||||||
|
.where('tokens.id', '=', token)
|
||||||
|
.select('owner')
|
||||||
|
.executeTakeFirst();
|
||||||
|
|
||||||
|
if (existingToken != null) {
|
||||||
|
existingUser = await db
|
||||||
|
.selectFrom('users')
|
||||||
|
.where('users.id', '=', existingToken.owner)
|
||||||
|
.selectAll()
|
||||||
|
.executeTakeFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existingUser == null) return redirect("/jams/");
|
||||||
|
|
||||||
|
const judgementid = params.judgementid;
|
||||||
|
|
||||||
|
if (judgementid == null) return notFound();
|
||||||
|
|
||||||
|
// It's a JSONJamTable. I don't know why TS hates `number` => `string` conversion.
|
||||||
|
let editingJudgement = await db
|
||||||
|
.selectFrom('judgements')
|
||||||
|
.where('judgements.id', '=', judgementid)
|
||||||
|
.selectAll()
|
||||||
|
.executeTakeFirst() as unknown as JSONJudgementTable;
|
||||||
|
|
||||||
|
if (editingJudgement == null) return notFound();
|
||||||
|
|
||||||
|
if (!existingUser.admin && editingJudgement.author_id != existingUser.id) return (
|
||||||
|
<MainLayout currentPage="/jams/" title="Delete Judgement" subtitle="Jams" backButton>
|
||||||
|
<h1>Can't delete this judgement</h1>
|
||||||
|
<p>You did not publish this judgement</p>
|
||||||
|
</MainLayout>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MainLayout currentPage="/jams/" title="Delete Judgement" subtitle="Jams" backButton>
|
||||||
|
<p>Deleting "<a href={`/jams/content/${editingJudgement.content_id}?until=${editingJudgement.published}`}>{editingJudgement.content}</a>"</p>
|
||||||
|
<ConditionalNull condition={existingUser != null}>
|
||||||
|
<p><small>Logged in as <b>{existingUser?.username}@{existingUser?.instance}</b></small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
<Form judgementID={editingJudgement.id} contentID={editingJudgement.content_id} />
|
||||||
|
</MainLayout>
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
'use client';
|
||||||
|
import React from "react";
|
||||||
|
import { ErrorMessage, useFormik } from "formik";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import { ConditionalNull } from "@/components/utility/Conditional";
|
||||||
|
import { JSONContentTable } from "@/lib/mastoauth/realtypes";
|
||||||
|
|
||||||
|
export function Form({contentID, preset}:{contentID:string, preset:Partial<JSONContentTable>}) {
|
||||||
|
const router = useRouter();
|
||||||
|
const formik = useFormik({
|
||||||
|
initialValues: preset,
|
||||||
|
onSubmit: async (values) => {
|
||||||
|
const submitRequest = await fetch(`/jams/api/content/${contentID}`, {
|
||||||
|
method: "PATCH",
|
||||||
|
body: JSON.stringify(values)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (submitRequest.ok) {
|
||||||
|
router.push(`/jams/content/${contentID}/`);
|
||||||
|
} else {
|
||||||
|
formik.setSubmitting(false);
|
||||||
|
if (submitRequest.status == 400) {
|
||||||
|
let errors:string[]|null = null;
|
||||||
|
try {
|
||||||
|
errors = await submitRequest.json();
|
||||||
|
} catch (err) { }; // No body. Skill issue
|
||||||
|
if (errors == null) return;
|
||||||
|
let transformedErrors:{[key:string]:string} = {};
|
||||||
|
errors.forEach((string) => transformedErrors[string] = "Something's wrong here");
|
||||||
|
formik.setErrors(transformedErrors);
|
||||||
|
} else {
|
||||||
|
formik.setErrors({
|
||||||
|
name: "Something went wrong..."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={formik.handleSubmit}>
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="name">Name</label></p>
|
||||||
|
<input
|
||||||
|
id="name"
|
||||||
|
name="name"
|
||||||
|
type="text"
|
||||||
|
onChange={formik.handleChange}
|
||||||
|
value={formik.values.name}
|
||||||
|
/>
|
||||||
|
<ConditionalNull condition={formik.touched.name != null && formik.errors.name != null}>
|
||||||
|
<p><small>Error: {formik.errors.name}</small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="description">Description</label></p>
|
||||||
|
<textarea
|
||||||
|
id="description"
|
||||||
|
name="description"
|
||||||
|
onChange={formik.handleChange}
|
||||||
|
value={formik.values.description}
|
||||||
|
/>
|
||||||
|
<ConditionalNull condition={formik.touched.description != null && formik.errors.description != null}>
|
||||||
|
<p><small>Error: {formik.errors.description}</small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="url">URL</label></p>
|
||||||
|
<input
|
||||||
|
id="url"
|
||||||
|
name="url"
|
||||||
|
type="url"
|
||||||
|
onChange={formik.handleChange}
|
||||||
|
value={formik.values.url}
|
||||||
|
/>
|
||||||
|
<ConditionalNull condition={formik.touched.url != null && formik.errors.url != null}>
|
||||||
|
<p><small>Error: {formik.errors.url}</small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="submit">Done?</label></p>
|
||||||
|
<input id="submit" name="submit" type="submit" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
|
||||||
|
import { Conditional, ConditionalNull } from "@/components/utility/Conditional";
|
||||||
|
import { MainLayout } from "@/layout/MainLayout/MainLayout";
|
||||||
|
import { db } from "@/lib/mastoauth/kysely";
|
||||||
|
import { JSONContentTable, JSONJamTable } from "@/lib/mastoauth/realtypes";
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
import { notFound, redirect } from "next/navigation";
|
||||||
|
import { Form } from "./components/form";
|
||||||
|
|
||||||
|
export default async function Home({
|
||||||
|
params
|
||||||
|
}: {
|
||||||
|
params: {
|
||||||
|
contentid: string
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
const cookieStore = cookies();
|
||||||
|
const token = cookieStore.get('token')?.value;
|
||||||
|
let existingUser;
|
||||||
|
if (token != null) {
|
||||||
|
let existingToken = await db
|
||||||
|
.selectFrom('tokens')
|
||||||
|
.where('tokens.id', '=', token)
|
||||||
|
.select('owner')
|
||||||
|
.executeTakeFirst();
|
||||||
|
|
||||||
|
if (existingToken != null) {
|
||||||
|
existingUser = await db
|
||||||
|
.selectFrom('users')
|
||||||
|
.where('users.id', '=', existingToken.owner)
|
||||||
|
.selectAll()
|
||||||
|
.executeTakeFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existingUser == null) return redirect("/jams/");
|
||||||
|
|
||||||
|
const contentid = params.contentid;
|
||||||
|
|
||||||
|
if (contentid == null) return notFound();
|
||||||
|
|
||||||
|
// It's a JSONJamTable. I don't know why TS hates `number` => `string` conversion.
|
||||||
|
let editingContent = await db
|
||||||
|
.selectFrom('content')
|
||||||
|
.where('content.id', '=', contentid)
|
||||||
|
.select(['id','name','description','url'])
|
||||||
|
.executeTakeFirst() as unknown as JSONContentTable;
|
||||||
|
|
||||||
|
if (editingContent == null) return notFound();
|
||||||
|
|
||||||
|
if (!existingUser.admin && editingContent.author_id != existingUser.id) return (
|
||||||
|
<MainLayout currentPage="/jams/" title="Edit Submission" subtitle="Jams" backButton>
|
||||||
|
<h1>Can't edit this submission</h1>
|
||||||
|
<p>You do not own this submission</p>
|
||||||
|
</MainLayout>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MainLayout currentPage="/jams/" title="Edit Submission" subtitle="Jams" backButton>
|
||||||
|
<p>Editing <a href={`/jams/content/${editingContent.id}`}>{editingContent.name}</a></p>
|
||||||
|
<ConditionalNull condition={existingUser != null}>
|
||||||
|
<p><small>Logged in as <b>{existingUser?.username}@{existingUser?.instance}</b></small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
<Form contentID={editingContent.id} preset={editingContent} />
|
||||||
|
</MainLayout>
|
||||||
|
)
|
||||||
|
}
|
115
src/app/jams/(manip)/edit/jam/[jamid]/components/form.tsx
Normal file
115
src/app/jams/(manip)/edit/jam/[jamid]/components/form.tsx
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
'use client';
|
||||||
|
import React from "react";
|
||||||
|
import { ErrorMessage, useFormik } from "formik";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import { ConditionalNull } from "@/components/utility/Conditional";
|
||||||
|
import { JSONContentTable, JSONJamTable } from "@/lib/mastoauth/realtypes";
|
||||||
|
|
||||||
|
export function Form({jamID, preset}:{jamID:string, preset:{
|
||||||
|
name: string,
|
||||||
|
description: string,
|
||||||
|
date_start: string,
|
||||||
|
date_end: string
|
||||||
|
}}) {
|
||||||
|
const correctPreset = {
|
||||||
|
...preset,
|
||||||
|
date_start: new Date(parseInt(preset.date_start)).toISOString().slice(0, -8),
|
||||||
|
date_end: new Date(parseInt(preset.date_end)).toISOString().slice(0, -8)
|
||||||
|
}
|
||||||
|
const router = useRouter();
|
||||||
|
const formik = useFormik({
|
||||||
|
initialValues: correctPreset,
|
||||||
|
onSubmit: async (values) => {
|
||||||
|
const correctValues = {
|
||||||
|
...values,
|
||||||
|
date_start: new Date(values.date_start).getTime(),
|
||||||
|
date_end: new Date(values.date_end).getTime(),
|
||||||
|
}
|
||||||
|
const submitRequest = await fetch(`/jams/api/jams/${jamID}`, {
|
||||||
|
method: "PATCH",
|
||||||
|
body: JSON.stringify(correctValues)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (submitRequest.ok) {
|
||||||
|
router.push(`/jams/jam/${jamID}/`);
|
||||||
|
} else {
|
||||||
|
formik.setSubmitting(false);
|
||||||
|
if (submitRequest.status == 400) {
|
||||||
|
let errors:string[]|null = null;
|
||||||
|
try {
|
||||||
|
errors = await submitRequest.json();
|
||||||
|
} catch (err) { }; // No body. Skill issue
|
||||||
|
if (errors == null) return;
|
||||||
|
let transformedErrors:{[key:string]:string} = {};
|
||||||
|
errors.forEach((string) => transformedErrors[string] = "Something's wrong here");
|
||||||
|
formik.setErrors(transformedErrors);
|
||||||
|
} else {
|
||||||
|
formik.setErrors({
|
||||||
|
name: "Something went wrong..."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={formik.handleSubmit}>
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="name">Name</label></p>
|
||||||
|
<input
|
||||||
|
id="name"
|
||||||
|
name="name"
|
||||||
|
type="text"
|
||||||
|
onChange={formik.handleChange}
|
||||||
|
value={formik.values.name}
|
||||||
|
/>
|
||||||
|
<ConditionalNull condition={formik.touched.name != null && formik.errors.name != null}>
|
||||||
|
<p><small>Error: {formik.errors.name}</small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="description">Description</label></p>
|
||||||
|
<textarea
|
||||||
|
id="description"
|
||||||
|
name="description"
|
||||||
|
onChange={formik.handleChange}
|
||||||
|
value={formik.values.description}
|
||||||
|
/>
|
||||||
|
<ConditionalNull condition={formik.touched.description != null && formik.errors.description != null}>
|
||||||
|
<p><small>Error: {formik.errors.description}</small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="date_start">Date Start</label></p>
|
||||||
|
<input
|
||||||
|
id="date_start"
|
||||||
|
name="date_start"
|
||||||
|
type="datetime-local"
|
||||||
|
onChange={formik.handleChange}
|
||||||
|
value={formik.values.date_start}
|
||||||
|
/>
|
||||||
|
<ConditionalNull condition={formik.touched.date_start != null && formik.errors.date_start != null}>
|
||||||
|
<p><small>Error: {formik.errors.date_start}</small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="date_end">Date End</label></p>
|
||||||
|
<input
|
||||||
|
id="date_end"
|
||||||
|
name="date_end"
|
||||||
|
type="datetime-local"
|
||||||
|
onChange={formik.handleChange}
|
||||||
|
value={formik.values.date_end}
|
||||||
|
/>
|
||||||
|
<ConditionalNull condition={formik.touched.date_end != null && formik.errors.date_end != null}>
|
||||||
|
<p><small>Error: {formik.errors.date_end}</small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="submit">Done?</label></p>
|
||||||
|
<input id="submit" name="submit" type="submit" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
|
||||||
|
import { Conditional, ConditionalNull } from "@/components/utility/Conditional";
|
||||||
|
import { MainLayout } from "@/layout/MainLayout/MainLayout";
|
||||||
|
import { db } from "@/lib/mastoauth/kysely";
|
||||||
|
import { JSONContentTable, JSONJamTable } from "@/lib/mastoauth/realtypes";
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
import { notFound, redirect } from "next/navigation";
|
||||||
|
import { Form } from "./components/form";
|
||||||
|
|
||||||
|
export default async function Home({
|
||||||
|
params
|
||||||
|
}: {
|
||||||
|
params: {
|
||||||
|
jamid: string
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
const cookieStore = cookies();
|
||||||
|
const token = cookieStore.get('token')?.value;
|
||||||
|
let existingUser;
|
||||||
|
if (token != null) {
|
||||||
|
let existingToken = await db
|
||||||
|
.selectFrom('tokens')
|
||||||
|
.where('tokens.id', '=', token)
|
||||||
|
.select('owner')
|
||||||
|
.executeTakeFirst();
|
||||||
|
|
||||||
|
if (existingToken != null) {
|
||||||
|
existingUser = await db
|
||||||
|
.selectFrom('users')
|
||||||
|
.where('users.id', '=', existingToken.owner)
|
||||||
|
.selectAll()
|
||||||
|
.executeTakeFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existingUser == null) return redirect("/jams/");
|
||||||
|
|
||||||
|
const jamid = params.jamid;
|
||||||
|
|
||||||
|
if (jamid == null) return notFound();
|
||||||
|
|
||||||
|
// It's a JSONJamTable. I don't know why TS hates `number` => `string` conversion.
|
||||||
|
let editingJam = await db
|
||||||
|
.selectFrom('jams')
|
||||||
|
.where('jams.id', '=', jamid)
|
||||||
|
.select(['id','name','description','date_start','date_end'])
|
||||||
|
.executeTakeFirst() as unknown as JSONJamTable;
|
||||||
|
|
||||||
|
if (editingJam == null) return notFound();
|
||||||
|
|
||||||
|
if (!existingUser.admin && editingJam.author_id != existingUser.id) return (
|
||||||
|
<MainLayout currentPage="/jams/" title="Edit Jam" subtitle="Jams" backButton>
|
||||||
|
<h1>Can't edit this Jam</h1>
|
||||||
|
<p>You do not own this Jam</p>
|
||||||
|
</MainLayout>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MainLayout currentPage="/jams/" title="Edit Jam" subtitle="Jams" backButton>
|
||||||
|
<p>Editing <a href={`/jams/content/${editingJam.id}`}>{editingJam.name}</a></p>
|
||||||
|
<ConditionalNull condition={existingUser != null}>
|
||||||
|
<p><small>Logged in as <b>{existingUser?.username}@{existingUser?.instance}</b></small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
<Form jamID={editingJam.id} preset={editingJam} />
|
||||||
|
</MainLayout>
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
'use client';
|
||||||
|
import React from "react";
|
||||||
|
import { ErrorMessage, useFormik } from "formik";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import { ConditionalNull } from "@/components/utility/Conditional";
|
||||||
|
import { JSONContentTable, JSONJudgementTable } from "@/lib/mastoauth/realtypes";
|
||||||
|
|
||||||
|
export function Form({judgementID, preset}:{judgementID:string, preset:JSONJudgementTable}) {
|
||||||
|
const router = useRouter();
|
||||||
|
const formik = useFormik({
|
||||||
|
initialValues: {
|
||||||
|
content: preset.content
|
||||||
|
},
|
||||||
|
onSubmit: async (values) => {
|
||||||
|
const submitRequest = await fetch(`/jams/api/content/${preset.content_id}/judgements/${judgementID}`, {
|
||||||
|
method: "PATCH",
|
||||||
|
body: JSON.stringify(values)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (submitRequest.ok) {
|
||||||
|
router.push(`/jams/content/${preset.content_id}?since=${preset.published}`);
|
||||||
|
} else {
|
||||||
|
formik.setSubmitting(false);
|
||||||
|
if (submitRequest.status == 400) {
|
||||||
|
let errors:string[]|null = null;
|
||||||
|
try {
|
||||||
|
errors = await submitRequest.json();
|
||||||
|
} catch (err) { }; // No body. Skill issue
|
||||||
|
if (errors == null) return;
|
||||||
|
let transformedErrors:{[key:string]:string} = {};
|
||||||
|
errors.forEach((string) => transformedErrors[string] = "Something's wrong here");
|
||||||
|
formik.setErrors(transformedErrors);
|
||||||
|
} else {
|
||||||
|
formik.setErrors({
|
||||||
|
content: "Something went wrong..."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={formik.handleSubmit}>
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="content">Content</label></p>
|
||||||
|
<textarea
|
||||||
|
id="content"
|
||||||
|
name="content"
|
||||||
|
onChange={formik.handleChange}
|
||||||
|
value={formik.values.content}
|
||||||
|
/>
|
||||||
|
<ConditionalNull condition={formik.touched.content != null && formik.errors.content != null}>
|
||||||
|
<p><small>Error: {formik.errors.content}</small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="submit">Done?</label></p>
|
||||||
|
<input id="submit" name="submit" type="submit" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
|
||||||
|
import { Conditional, ConditionalNull } from "@/components/utility/Conditional";
|
||||||
|
import { MainLayout } from "@/layout/MainLayout/MainLayout";
|
||||||
|
import { db } from "@/lib/mastoauth/kysely";
|
||||||
|
import { JSONContentTable, JSONJamTable, JSONJudgementTable } from "@/lib/mastoauth/realtypes";
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
import { notFound, redirect } from "next/navigation";
|
||||||
|
import { Form } from "./components/form";
|
||||||
|
|
||||||
|
export default async function Home({
|
||||||
|
params
|
||||||
|
}: {
|
||||||
|
params: {
|
||||||
|
judgementid: string
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
const cookieStore = cookies();
|
||||||
|
const token = cookieStore.get('token')?.value;
|
||||||
|
let existingUser;
|
||||||
|
if (token != null) {
|
||||||
|
let existingToken = await db
|
||||||
|
.selectFrom('tokens')
|
||||||
|
.where('tokens.id', '=', token)
|
||||||
|
.select('owner')
|
||||||
|
.executeTakeFirst();
|
||||||
|
|
||||||
|
if (existingToken != null) {
|
||||||
|
existingUser = await db
|
||||||
|
.selectFrom('users')
|
||||||
|
.where('users.id', '=', existingToken.owner)
|
||||||
|
.selectAll()
|
||||||
|
.executeTakeFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existingUser == null) return redirect("/jams/");
|
||||||
|
|
||||||
|
const judgementid = params.judgementid;
|
||||||
|
|
||||||
|
if (judgementid == null) return notFound();
|
||||||
|
|
||||||
|
// It's a JSONJamTable. I don't know why TS hates `number` => `string` conversion.
|
||||||
|
let editingJudgement = await db
|
||||||
|
.selectFrom('judgements')
|
||||||
|
.where('judgements.id', '=', judgementid)
|
||||||
|
.select(['content_id', 'content', 'published'])
|
||||||
|
.executeTakeFirst() as unknown as JSONJudgementTable;
|
||||||
|
|
||||||
|
if (editingJudgement == null) return notFound();
|
||||||
|
|
||||||
|
if (!existingUser.admin && editingJudgement.author_id != existingUser.id) return (
|
||||||
|
<MainLayout currentPage="/jams/" title="Edit Judgement" subtitle="Jams" backButton>
|
||||||
|
<h1>Can't edit this judgement</h1>
|
||||||
|
<p>You do not own this judgement</p>
|
||||||
|
</MainLayout>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MainLayout currentPage="/jams/" title="Edit Judgement" subtitle="Jams" backButton>
|
||||||
|
<p>Editing judgement "<a href={`/jams/content/${editingJudgement.content_id}?since=${editingJudgement.published}`}>{editingJudgement.content}</a>"</p>
|
||||||
|
<ConditionalNull condition={existingUser != null}>
|
||||||
|
<p><small>Logged in as <b>{existingUser?.username}@{existingUser?.instance}</b></small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
<Form judgementID={judgementid} preset={editingJudgement} />
|
||||||
|
</MainLayout>
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,36 +1,94 @@
|
||||||
'use client';
|
'use client';
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useFormik } from "formik";
|
import { ErrorMessage, useFormik } from "formik";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import { ConditionalNull } from "@/components/utility/Conditional";
|
||||||
|
|
||||||
export function Form() {
|
export function Form({jamID}:{jamID:string}) {
|
||||||
|
const router = useRouter();
|
||||||
const formik = useFormik({
|
const formik = useFormik({
|
||||||
initialValues: {
|
initialValues: {
|
||||||
email: '',
|
name: '',
|
||||||
|
description: '',
|
||||||
|
url: '',
|
||||||
},
|
},
|
||||||
onSubmit: values => {
|
onSubmit: async (values) => {
|
||||||
alert(JSON.stringify(values, null, 2));
|
const submitRequest = await fetch(`/jams/api/jams/${jamID}/content`, {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(values)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (submitRequest.ok) {
|
||||||
|
let id:string = await submitRequest.text();
|
||||||
|
|
||||||
|
if (id == null) return;
|
||||||
|
|
||||||
|
router.push(`/jams/content/${id}/`);
|
||||||
|
} else {
|
||||||
|
formik.setSubmitting(false);
|
||||||
|
if (submitRequest.status == 400) {
|
||||||
|
let errors:string[]|null = null;
|
||||||
|
try {
|
||||||
|
errors = await submitRequest.json();
|
||||||
|
} catch (err) { }; // No body. Skill issue
|
||||||
|
if (errors == null) return;
|
||||||
|
let transformedErrors:{[key:string]:string} = {};
|
||||||
|
errors.forEach((string) => transformedErrors[string] = "Something's wrong here");
|
||||||
|
formik.setErrors(transformedErrors);
|
||||||
|
} else {
|
||||||
|
formik.setErrors({
|
||||||
|
name: "Something went wrong..."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={formik.handleSubmit}>
|
<form onSubmit={formik.handleSubmit}>
|
||||||
<label htmlFor="email">Email Address</label>
|
<div>
|
||||||
<input
|
<p><label htmlFor="name">Name</label></p>
|
||||||
id="name"
|
<input
|
||||||
name="name"
|
id="name"
|
||||||
type="text"
|
name="name"
|
||||||
onChange={formik.handleChange}
|
type="text"
|
||||||
value={formik.values.email}
|
onChange={formik.handleChange}
|
||||||
/>
|
value={formik.values.name}
|
||||||
<input
|
/>
|
||||||
id="name"
|
<ConditionalNull condition={formik.touched.name != null && formik.errors.name != null}>
|
||||||
name="name"
|
<p><small>Error: {formik.errors.name}</small></p>
|
||||||
type="text"
|
</ConditionalNull>
|
||||||
onChange={formik.handleChange}
|
</div>
|
||||||
value={formik.values.email}
|
<div>
|
||||||
/>
|
<p><label htmlFor="description">Description</label></p>
|
||||||
|
<textarea
|
||||||
<button type="submit">Submit</button>
|
id="description"
|
||||||
|
name="description"
|
||||||
|
onChange={formik.handleChange}
|
||||||
|
value={formik.values.description}
|
||||||
|
/>
|
||||||
|
<ConditionalNull condition={formik.touched.description != null && formik.errors.description != null}>
|
||||||
|
<p><small>Error: {formik.errors.description}</small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="url">URL</label></p>
|
||||||
|
<input
|
||||||
|
id="url"
|
||||||
|
name="url"
|
||||||
|
type="url"
|
||||||
|
onChange={formik.handleChange}
|
||||||
|
value={formik.values.url}
|
||||||
|
/>
|
||||||
|
<ConditionalNull condition={formik.touched.url != null && formik.errors.url != null}>
|
||||||
|
<p><small>Error: {formik.errors.url}</small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="submit">Done?</label></p>
|
||||||
|
<input id="submit" name="submit" type="submit" />
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -33,6 +33,8 @@ export default async function Home({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (existingUser == null) return redirect("/jams/");
|
||||||
|
|
||||||
const jamid = params.jamid;
|
const jamid = params.jamid;
|
||||||
|
|
||||||
if (jamid == null) return notFound();
|
if (jamid == null) return notFound();
|
||||||
|
@ -44,14 +46,14 @@ export default async function Home({
|
||||||
.selectAll()
|
.selectAll()
|
||||||
.executeTakeFirst() as unknown as JSONJamTable;
|
.executeTakeFirst() as unknown as JSONJamTable;
|
||||||
|
|
||||||
// const started = Date.now() >= parseInt(parentJam.date_start);
|
if (parentJam == null) return notFound();
|
||||||
// const ended = Date.now() >= parseInt(parentJam.date_end);
|
|
||||||
const started = true;
|
const started = Date.now() >= parseInt(parentJam.date_start);
|
||||||
const ended = false;
|
const ended = Date.now() >= parseInt(parentJam.date_end);
|
||||||
|
|
||||||
if (!started || ended) return (
|
if (!started || ended) return (
|
||||||
<MainLayout currentPage="/jams/" title="New Submission" subtitle="Jams" backButton>
|
<MainLayout currentPage="/jams/" title="New Submission" subtitle="Jams" backButton>
|
||||||
<h1>Can't submit to this jam</h1>
|
<h1>Can't submit to this Jam</h1>
|
||||||
<ConditionalNull condition={!started}>
|
<ConditionalNull condition={!started}>
|
||||||
<p>The jam starts at {new Date(parseInt(parentJam.date_start)).toLocaleString('en-us', {
|
<p>The jam starts at {new Date(parseInt(parentJam.date_start)).toLocaleString('en-us', {
|
||||||
timeZoneName: "long"
|
timeZoneName: "long"
|
||||||
|
@ -65,15 +67,13 @@ export default async function Home({
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (existingUser == null) return redirect("/jams/");
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainLayout currentPage="/jams/" title="New Submission" subtitle="Jams" backButton>
|
<MainLayout currentPage="/jams/" title="New Submission" subtitle="Jams" backButton>
|
||||||
<p>Submit something to <b>{parentJam.name}</b></p>
|
<p>Submit something to <a href={`/jams/jam/${parentJam.id}`}>{parentJam.name}</a></p>
|
||||||
<ConditionalNull condition={existingUser != null}>
|
<ConditionalNull condition={existingUser != null}>
|
||||||
<p><small>Logged in as <b>{existingUser?.username}@{existingUser?.instance}</b></small></p>
|
<p><small>Logged in as <b>{existingUser?.username}@{existingUser?.instance}</b></small></p>
|
||||||
</ConditionalNull>
|
</ConditionalNull>
|
||||||
<Form />
|
<Form jamID={parentJam.id} />
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
)
|
)
|
||||||
}
|
}
|
113
src/app/jams/(manip)/new/jam/components/form.tsx
Normal file
113
src/app/jams/(manip)/new/jam/components/form.tsx
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
'use client';
|
||||||
|
import React from "react";
|
||||||
|
import { ErrorMessage, useFormik } from "formik";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import { ConditionalNull } from "@/components/utility/Conditional";
|
||||||
|
|
||||||
|
export function Form() {
|
||||||
|
const router = useRouter();
|
||||||
|
const formik = useFormik({
|
||||||
|
initialValues: {
|
||||||
|
name: '',
|
||||||
|
description: '',
|
||||||
|
date_start: '',
|
||||||
|
date_end: '',
|
||||||
|
},
|
||||||
|
onSubmit: async (values) => {
|
||||||
|
const correctValues = {
|
||||||
|
...values,
|
||||||
|
date_start: new Date(values.date_start).getTime(),
|
||||||
|
date_end: new Date(values.date_end).getTime(),
|
||||||
|
}
|
||||||
|
const submitRequest = await fetch(`/jams/api/jams`, {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(correctValues)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (submitRequest.ok) {
|
||||||
|
let id:string = await submitRequest.text();
|
||||||
|
|
||||||
|
if (id == null) return;
|
||||||
|
|
||||||
|
router.push(`/jams/jam/${id}/`);
|
||||||
|
} else {
|
||||||
|
formik.setSubmitting(false);
|
||||||
|
if (submitRequest.status == 400) {
|
||||||
|
let errors:string[]|null = null;
|
||||||
|
try {
|
||||||
|
errors = await submitRequest.json();
|
||||||
|
} catch (err) { }; // No body. Skill issue
|
||||||
|
if (errors == null) return;
|
||||||
|
let transformedErrors:{[key:string]:string} = {};
|
||||||
|
errors.forEach((string) => transformedErrors[string] = "Something's wrong here");
|
||||||
|
formik.setErrors(transformedErrors);
|
||||||
|
} else {
|
||||||
|
formik.setErrors({
|
||||||
|
name: "Something went wrong..."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={formik.handleSubmit}>
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="name">Name</label></p>
|
||||||
|
<input
|
||||||
|
id="name"
|
||||||
|
name="name"
|
||||||
|
type="text"
|
||||||
|
onChange={formik.handleChange}
|
||||||
|
value={formik.values.name}
|
||||||
|
/>
|
||||||
|
<ConditionalNull condition={formik.touched.name != null && formik.errors.name != null}>
|
||||||
|
<p><small>Error: {formik.errors.name}</small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="description">Description</label></p>
|
||||||
|
<textarea
|
||||||
|
id="description"
|
||||||
|
name="description"
|
||||||
|
onChange={formik.handleChange}
|
||||||
|
value={formik.values.description}
|
||||||
|
/>
|
||||||
|
<ConditionalNull condition={formik.touched.description != null && formik.errors.description != null}>
|
||||||
|
<p><small>Error: {formik.errors.description}</small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="date_start">Date Start</label></p>
|
||||||
|
<input
|
||||||
|
id="date_start"
|
||||||
|
name="date_start"
|
||||||
|
type="datetime-local"
|
||||||
|
onChange={formik.handleChange}
|
||||||
|
value={formik.values.date_start}
|
||||||
|
/>
|
||||||
|
<ConditionalNull condition={formik.touched.date_start != null && formik.errors.date_start != null}>
|
||||||
|
<p><small>Error: {formik.errors.date_start}</small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="date_end">Date End</label></p>
|
||||||
|
<input
|
||||||
|
id="date_end"
|
||||||
|
name="date_end"
|
||||||
|
type="datetime-local"
|
||||||
|
onChange={formik.handleChange}
|
||||||
|
value={formik.values.date_end}
|
||||||
|
/>
|
||||||
|
<ConditionalNull condition={formik.touched.date_end != null && formik.errors.date_end != null}>
|
||||||
|
<p><small>Error: {formik.errors.date_end}</small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="submit">Done?</label></p>
|
||||||
|
<input id="submit" name="submit" type="submit" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
|
||||||
|
import { Conditional, ConditionalNull } from "@/components/utility/Conditional";
|
||||||
|
import { MainLayout } from "@/layout/MainLayout/MainLayout";
|
||||||
|
import { db } from "@/lib/mastoauth/kysely";
|
||||||
|
import { JSONJamTable } from "@/lib/mastoauth/realtypes";
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
import { notFound, redirect } from "next/navigation";
|
||||||
|
import { Form } from "./components/form";
|
||||||
|
|
||||||
|
export default async function Home() {
|
||||||
|
const cookieStore = cookies();
|
||||||
|
const token = cookieStore.get('token')?.value;
|
||||||
|
let existingUser;
|
||||||
|
if (token != null) {
|
||||||
|
let existingToken = await db
|
||||||
|
.selectFrom('tokens')
|
||||||
|
.where('tokens.id', '=', token)
|
||||||
|
.select('owner')
|
||||||
|
.executeTakeFirst();
|
||||||
|
|
||||||
|
if (existingToken != null) {
|
||||||
|
existingUser = await db
|
||||||
|
.selectFrom('users')
|
||||||
|
.where('users.id', '=', existingToken.owner)
|
||||||
|
.selectAll()
|
||||||
|
.executeTakeFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existingUser == null) return redirect("/jams/");
|
||||||
|
|
||||||
|
if (!existingUser.admin) return (
|
||||||
|
<MainLayout currentPage="/jams/" title="New Jam" subtitle="Jams" backButton>
|
||||||
|
<h1>Can't create a new Jam</h1>
|
||||||
|
<p>Non-admins cannot create Jams.</p>
|
||||||
|
</MainLayout>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MainLayout currentPage="/jams/" title="New Jam" subtitle="Jams" backButton>
|
||||||
|
<p>Create a new Jam.</p>
|
||||||
|
<ConditionalNull condition={existingUser != null}>
|
||||||
|
<p><small>Logged in as <b>{existingUser?.username}@{existingUser?.instance}</b></small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
<Form />
|
||||||
|
</MainLayout>
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
'use client';
|
||||||
|
import React from "react";
|
||||||
|
import { ErrorMessage, useFormik } from "formik";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import { ConditionalNull } from "@/components/utility/Conditional";
|
||||||
|
|
||||||
|
export function Form({contentID}:{contentID:string}) {
|
||||||
|
const router = useRouter();
|
||||||
|
const formik = useFormik({
|
||||||
|
initialValues: {
|
||||||
|
content: '',
|
||||||
|
},
|
||||||
|
onSubmit: async (values) => {
|
||||||
|
const submitRequest = await fetch(`/jams/api/content/${contentID}/judgements`, {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(values)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (submitRequest.ok) {
|
||||||
|
let id:string = await submitRequest.text();
|
||||||
|
|
||||||
|
if (id == null) return;
|
||||||
|
|
||||||
|
router.push(`/jams/content/${contentID}/`);
|
||||||
|
} else {
|
||||||
|
formik.setSubmitting(false);
|
||||||
|
if (submitRequest.status == 400) {
|
||||||
|
let errors:string[]|null = null;
|
||||||
|
try {
|
||||||
|
errors = await submitRequest.json();
|
||||||
|
} catch (err) { }; // No body. Skill issue
|
||||||
|
if (errors == null) return;
|
||||||
|
let transformedErrors:{[key:string]:string} = {};
|
||||||
|
errors.forEach((string) => transformedErrors[string] = "Something's wrong here");
|
||||||
|
formik.setErrors(transformedErrors);
|
||||||
|
} else {
|
||||||
|
formik.setErrors({
|
||||||
|
content: "Something went wrong..."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={formik.handleSubmit}>
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="content">Content</label></p>
|
||||||
|
<textarea
|
||||||
|
id="content"
|
||||||
|
name="content"
|
||||||
|
onChange={formik.handleChange}
|
||||||
|
value={formik.values.content}
|
||||||
|
/>
|
||||||
|
<ConditionalNull condition={formik.touched.content != null && formik.errors.content != null}>
|
||||||
|
<p><small>Error: {formik.errors.content}</small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p><label htmlFor="submit">Done?</label></p>
|
||||||
|
<input id="submit" name="submit" type="submit" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
|
||||||
|
import { Conditional, ConditionalNull } from "@/components/utility/Conditional";
|
||||||
|
import { MainLayout } from "@/layout/MainLayout/MainLayout";
|
||||||
|
import { db } from "@/lib/mastoauth/kysely";
|
||||||
|
import { JSONContentTable, JSONJamTable } from "@/lib/mastoauth/realtypes";
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
import { notFound, redirect } from "next/navigation";
|
||||||
|
import { Form } from "./components/form";
|
||||||
|
|
||||||
|
export default async function Home({
|
||||||
|
params
|
||||||
|
}: {
|
||||||
|
params: {
|
||||||
|
contentid: string
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
const cookieStore = cookies();
|
||||||
|
const token = cookieStore.get('token')?.value;
|
||||||
|
let existingUser;
|
||||||
|
if (token != null) {
|
||||||
|
let existingToken = await db
|
||||||
|
.selectFrom('tokens')
|
||||||
|
.where('tokens.id', '=', token)
|
||||||
|
.select('owner')
|
||||||
|
.executeTakeFirst();
|
||||||
|
|
||||||
|
if (existingToken != null) {
|
||||||
|
existingUser = await db
|
||||||
|
.selectFrom('users')
|
||||||
|
.where('users.id', '=', existingToken.owner)
|
||||||
|
.selectAll()
|
||||||
|
.executeTakeFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existingUser == null) return redirect("/jams/");
|
||||||
|
|
||||||
|
const contentid = params.contentid;
|
||||||
|
|
||||||
|
if (contentid == null) return notFound();
|
||||||
|
|
||||||
|
// It's a JSONJamTable. I don't know why TS hates `number` => `string` conversion.
|
||||||
|
let parentContent = await db
|
||||||
|
.selectFrom('content')
|
||||||
|
.where('content.id', '=', contentid)
|
||||||
|
.selectAll()
|
||||||
|
.executeTakeFirst() as unknown as JSONContentTable;
|
||||||
|
|
||||||
|
if (parentContent == null) return notFound();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MainLayout currentPage="/jams/" title="New Submission" subtitle="Jams" backButton>
|
||||||
|
<p>Judge <a href={`/jams/content/${parentContent.id}`}>{parentContent.name}</a></p>
|
||||||
|
<ConditionalNull condition={existingUser != null}>
|
||||||
|
<p><small>Logged in as <b>{existingUser?.username}@{existingUser?.instance}</b></small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
<Form contentID={parentContent.id} />
|
||||||
|
</MainLayout>
|
||||||
|
)
|
||||||
|
}
|
|
@ -78,20 +78,20 @@ export async function PATCH(request: NextRequest, {params}: {params: {content:st
|
||||||
status: 401
|
status: 401
|
||||||
});
|
});
|
||||||
|
|
||||||
const id = params.content;
|
const id = params.judgement;
|
||||||
|
|
||||||
if (id == null) return new Response('', {
|
if (id == null) return new Response('', {
|
||||||
status: 400
|
status: 400
|
||||||
});
|
});
|
||||||
|
|
||||||
let updatingJudgement = await db
|
let updatingJudgement = await db
|
||||||
.selectFrom('judgements')
|
.selectFrom('judgements')
|
||||||
.where('judgements.content_id', '=', cid)
|
.where('judgements.content_id', '=', cid)
|
||||||
.where('judgements.id', '=', id)
|
.where('judgements.id', '=', id)
|
||||||
.select(['author_id'])
|
.select(['author_id'])
|
||||||
.executeTakeFirst();
|
.executeTakeFirst();
|
||||||
|
|
||||||
console.log(updatingJudgement, existingUser)
|
console.log(cid, id, updatingJudgement, existingUser)
|
||||||
|
|
||||||
if (updatingJudgement == null) return new Response('', {
|
if (updatingJudgement == null) return new Response('', {
|
||||||
status: 400
|
status: 400
|
||||||
|
@ -193,7 +193,7 @@ export async function DELETE(request: NextRequest, {params}: {params: {content:s
|
||||||
status: 401
|
status: 401
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(deletingJudgement, existingUser)
|
console.log(cid, id, deletingJudgement, existingUser)
|
||||||
|
|
||||||
if (deletingJudgement == null) return new Response('', {
|
if (deletingJudgement == null) return new Response('', {
|
||||||
status: 400
|
status: 400
|
||||||
|
|
|
@ -183,6 +183,14 @@ export async function DELETE(request: NextRequest, {params}: {params: {content:s
|
||||||
status: 401
|
status: 401
|
||||||
});
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await db
|
||||||
|
.deleteFrom('judgements')
|
||||||
|
.where('judgements.content_id', '=', id)
|
||||||
|
.execute();
|
||||||
|
} catch (err) {
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await db
|
await db
|
||||||
.deleteFrom('content')
|
.deleteFrom('content')
|
||||||
|
|
|
@ -156,6 +156,15 @@ export async function DELETE(request: NextRequest, {params}: {params: {jam:strin
|
||||||
status: 401
|
status: 401
|
||||||
});
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await db
|
||||||
|
.updateTable('content')
|
||||||
|
.set('content.jam_id', '')
|
||||||
|
.where('content.jam_id', '=', id)
|
||||||
|
.execute();
|
||||||
|
} catch (err) {
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await db
|
await db
|
||||||
.deleteFrom('jams')
|
.deleteFrom('jams')
|
||||||
|
|
|
@ -77,19 +77,21 @@ export async function POST(request: NextRequest) {
|
||||||
|
|
||||||
let newBody:JamTable = body;
|
let newBody:JamTable = body;
|
||||||
|
|
||||||
|
let curBody = {
|
||||||
|
id: nanoid(21),
|
||||||
|
author_id: existingUser.id,
|
||||||
|
name: newBody.name,
|
||||||
|
description: newBody.description,
|
||||||
|
date_start: newBody.date_start,
|
||||||
|
date_end: newBody.date_end,
|
||||||
|
created: Date.now()
|
||||||
|
};
|
||||||
|
|
||||||
let res;
|
let res;
|
||||||
try {
|
try {
|
||||||
res = await db
|
res = await db
|
||||||
.insertInto('jams')
|
.insertInto('jams')
|
||||||
.values({
|
.values(curBody)
|
||||||
id: nanoid(21),
|
|
||||||
author_id: existingUser.id,
|
|
||||||
name: newBody.name,
|
|
||||||
description: newBody.description,
|
|
||||||
date_start: newBody.date_start,
|
|
||||||
date_end: newBody.date_end,
|
|
||||||
created: Date.now()
|
|
||||||
})
|
|
||||||
.executeTakeFirstOrThrow();
|
.executeTakeFirstOrThrow();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return new Response('', {
|
return new Response('', {
|
||||||
|
@ -97,7 +99,7 @@ export async function POST(request: NextRequest) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Response(null, {
|
return new Response(curBody.id, {
|
||||||
status: 204
|
status: 200
|
||||||
})
|
})
|
||||||
}
|
}
|
|
@ -84,13 +84,18 @@ export default async function Home({
|
||||||
<MainLayout currentPage="/jams/" title={content.name} subtitle="Jams" backButton>
|
<MainLayout currentPage="/jams/" title={content.name} subtitle="Jams" backButton>
|
||||||
<h1>{content.name}</h1>
|
<h1>{content.name}</h1>
|
||||||
<p><a href={content.url} target="_blank">{content.url}</a></p>
|
<p><a href={content.url} target="_blank">{content.url}</a></p>
|
||||||
|
<ConditionalNull condition={submittedJam != null}>
|
||||||
<p><small>Submitted by <a href={`/jams/user/${contentOwner.id}`}>{`${contentOwner.username}@${contentOwner.instance}`}</a> to <a href={`/jams/jam/${submittedJam.id}?until=${content.submitted}`}>{submittedJam.name}</a> - {new Date(parseInt(content.submitted)).toDateString()}</small></p>
|
<p><small>Submitted by <a href={`/jams/user/${contentOwner.id}`}>{`${contentOwner.username}@${contentOwner.instance}`}</a> to <a href={`/jams/jam/${submittedJam.id}?until=${content.submitted}`}>{submittedJam.name}</a> - {new Date(parseInt(content.submitted)).toDateString()}</small></p>
|
||||||
|
</ConditionalNull>
|
||||||
|
<ConditionalNull condition={submittedJam == null}>
|
||||||
|
<p><small>Submitted by <a href={`/jams/user/${contentOwner.id}`}>{`${contentOwner.username}@${contentOwner.instance}`}</a> {new Date(parseInt(content.submitted)).toDateString()}</small></p>
|
||||||
|
</ConditionalNull>
|
||||||
<p>{content.description}</p>
|
<p>{content.description}</p>
|
||||||
<ConditionalNull condition={existingUser != null}>
|
<ConditionalNull condition={existingUser != null}>
|
||||||
<div>
|
<div>
|
||||||
<ConditionalNull condition={existingUser?.admin || content.author_id == content.id}><p><b>You have the ability to modify this submission.</b></p></ConditionalNull>
|
<ConditionalNull condition={existingUser?.admin || content.author_id == existingUser?.id}><p><b>You have the ability to modify this submission.</b></p></ConditionalNull>
|
||||||
<ConditionalNull condition={existingUser?.admin || content.author_id == content.id}><p><a href={`/jams/edit/content/${content.id}`}>Edit submission</a></p></ConditionalNull>
|
<ConditionalNull condition={existingUser?.admin || content.author_id == existingUser?.id}><p><a href={`/jams/edit/content/${content.id}`}>Edit submission</a></p></ConditionalNull>
|
||||||
<ConditionalNull condition={existingUser?.admin || content.author_id == content.id}><p><a href={`/jams/delete/content/${content.id}`}>Delete submission</a></p></ConditionalNull>
|
<ConditionalNull condition={existingUser?.admin || content.author_id == existingUser?.id}><p><a href={`/jams/delete/content/${content.id}`}>Delete submission</a></p></ConditionalNull>
|
||||||
<p><a href={`/jams/new/judgement/${content.id}`}>Judge this submission</a></p>
|
<p><a href={`/jams/new/judgement/${content.id}`}>Judge this submission</a></p>
|
||||||
</div>
|
</div>
|
||||||
</ConditionalNull>
|
</ConditionalNull>
|
||||||
|
@ -110,7 +115,7 @@ export default async function Home({
|
||||||
<h2><a href={`/jams/user/${judgementOwner.id}`}>{`${judgementOwner.username}@${judgementOwner.instance}`}</a></h2>
|
<h2><a href={`/jams/user/${judgementOwner.id}`}>{`${judgementOwner.username}@${judgementOwner.instance}`}</a></h2>
|
||||||
<ConditionalNull condition={existingUser != null}>
|
<ConditionalNull condition={existingUser != null}>
|
||||||
<div>
|
<div>
|
||||||
<ConditionalNull condition={existingUser?.admin || content.author_id == content.id}><p><a href={`/jams/edit/judgement/${judgement.id}`}>Edit judgement</a> - <a href={`/jams/delete/judgement/${judgement.id}`}>Delete judgement</a></p></ConditionalNull>
|
<ConditionalNull condition={existingUser?.admin || judgementOwner.id == existingUser?.id}><p><a href={`/jams/edit/judgement/${judgement.id}`}>Edit judgement</a> - <a href={`/jams/delete/judgement/${judgement.id}`}>Delete judgement</a></p></ConditionalNull>
|
||||||
</div>
|
</div>
|
||||||
</ConditionalNull>
|
</ConditionalNull>
|
||||||
<p><small>Published {new Date(parseInt(judgement.published)).toDateString()}</small></p>
|
<p><small>Published {new Date(parseInt(judgement.published)).toDateString()}</small></p>
|
||||||
|
@ -119,7 +124,7 @@ export default async function Home({
|
||||||
})}
|
})}
|
||||||
<div className="navigation">
|
<div className="navigation">
|
||||||
<ConditionalNull condition={curPage < curDate}>
|
<ConditionalNull condition={curPage < curDate}>
|
||||||
<Link href={`?until=${judgements.at(0)?.published}`}>Later</Link>
|
<Link href={`?`}>Later</Link>
|
||||||
</ConditionalNull>
|
</ConditionalNull>
|
||||||
{/* <ConditionalNull condition={curPage * 10 < blogs.data.total_posts}> */}
|
{/* <ConditionalNull condition={curPage * 10 < blogs.data.total_posts}> */}
|
||||||
<Link href={`?until=${judgements.at(-1)?.published}`}>Earlier</Link>
|
<Link href={`?until=${judgements.at(-1)?.published}`}>Earlier</Link>
|
||||||
|
|
|
@ -108,7 +108,7 @@ export default async function Home({
|
||||||
})}
|
})}
|
||||||
<div className="navigation">
|
<div className="navigation">
|
||||||
<ConditionalNull condition={curPage < curDate}>
|
<ConditionalNull condition={curPage < curDate}>
|
||||||
<Link href={`?until=${content.at(0)?.submitted}`}>Later</Link>
|
<Link href={`?`}>Later</Link>
|
||||||
</ConditionalNull>
|
</ConditionalNull>
|
||||||
{/* <ConditionalNull condition={curPage * 10 < blogs.data.total_posts}> */}
|
{/* <ConditionalNull condition={curPage * 10 < blogs.data.total_posts}> */}
|
||||||
<Link href={`?until=${content.at(-1)?.submitted}`}>Earlier</Link>
|
<Link href={`?until=${content.at(-1)?.submitted}`}>Earlier</Link>
|
||||||
|
|
|
@ -85,7 +85,7 @@ export default async function Home({
|
||||||
})}
|
})}
|
||||||
<div className="navigation">
|
<div className="navigation">
|
||||||
<ConditionalNull condition={curPage < curDate}>
|
<ConditionalNull condition={curPage < curDate}>
|
||||||
<Link href={`?until=${jams.at(0)?.created}`}>Later</Link>
|
<Link href={`?`}>Later</Link>
|
||||||
</ConditionalNull>
|
</ConditionalNull>
|
||||||
{/* <ConditionalNull condition={curPage * 10 < blogs.data.total_posts}> */}
|
{/* <ConditionalNull condition={curPage * 10 < blogs.data.total_posts}> */}
|
||||||
<Link href={`?until=${jams.at(-1)?.created}`}>Earlier</Link>
|
<Link href={`?until=${jams.at(-1)?.created}`}>Earlier</Link>
|
||||||
|
|
|
@ -138,7 +138,7 @@ export default async function Home({
|
||||||
})}
|
})}
|
||||||
{/* <div className="navigation">
|
{/* <div className="navigation">
|
||||||
<ConditionalNull condition={curPage < curDate}>
|
<ConditionalNull condition={curPage < curDate}>
|
||||||
<Link href={`?until=${content.at(0)?.submitted}`}>Later</Link>
|
<Link href={`?`}>Later</Link>
|
||||||
</ConditionalNull>
|
</ConditionalNull>
|
||||||
<Link href={`?until=${content.at(-1)?.submitted}`}>Earlier</Link>
|
<Link href={`?until=${content.at(-1)?.submitted}`}>Earlier</Link>
|
||||||
</div> */}
|
</div> */}
|
||||||
|
|
|
@ -25,8 +25,8 @@ export class MastoAuth {
|
||||||
async newApplication() {
|
async newApplication() {
|
||||||
let formData = new FormData();
|
let formData = new FormData();
|
||||||
formData.append('client_name', 'abtmtr.link Jams');
|
formData.append('client_name', 'abtmtr.link Jams');
|
||||||
// formData.append('redirect_uris', 'https://abtmtr.link/jams/oauth/code');
|
formData.append('redirect_uris', 'https://abtmtr.link/jams/oauth/code');
|
||||||
formData.append('redirect_uris', 'http://localhost:3000/jams/oauth/code');
|
// formData.append('redirect_uris', 'http://localhost:3000/jams/oauth/code');
|
||||||
formData.append('scopes', 'read');
|
formData.append('scopes', 'read');
|
||||||
formData.append('website', 'https://abtmtr.link/jams');
|
formData.append('website', 'https://abtmtr.link/jams');
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,16 @@ button {
|
||||||
transition: all 0.125s;
|
transition: all 0.125s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input:not([type="submit"]),
|
||||||
|
textarea {
|
||||||
|
width: 100%;
|
||||||
|
font-family: monospace;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
button:hover {
|
button:hover {
|
||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue