feat: mii descriptions
This commit is contained in:
parent
8753358a48
commit
398580e72b
7 changed files with 34 additions and 6 deletions
|
|
@ -0,0 +1,2 @@
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "miis" ADD COLUMN "description" VARCHAR(256);
|
||||||
|
|
@ -64,11 +64,12 @@ model Session {
|
||||||
}
|
}
|
||||||
|
|
||||||
model Mii {
|
model Mii {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
userId Int
|
userId Int
|
||||||
name String @db.VarChar(64)
|
name String @db.VarChar(64)
|
||||||
imageCount Int @default(0)
|
imageCount Int @default(0)
|
||||||
tags String[]
|
tags String[]
|
||||||
|
description String? @db.VarChar(256)
|
||||||
|
|
||||||
firstName String
|
firstName String
|
||||||
lastName String
|
lastName String
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ const uploadsDirectory = path.join(process.cwd(), "uploads");
|
||||||
const submitSchema = z.object({
|
const submitSchema = z.object({
|
||||||
name: nameSchema,
|
name: nameSchema,
|
||||||
tags: tagsSchema,
|
tags: tagsSchema,
|
||||||
|
description: z.string().trim().max(256).optional(),
|
||||||
qrBytesRaw: z
|
qrBytesRaw: z
|
||||||
.array(z.number(), { required_error: "A QR code is required" })
|
.array(z.number(), { required_error: "A QR code is required" })
|
||||||
.length(372, { message: "QR code size is not a valid Tomodachi Life QR code" }),
|
.length(372, { message: "QR code size is not a valid Tomodachi Life QR code" }),
|
||||||
|
|
@ -54,6 +55,7 @@ export async function POST(request: NextRequest) {
|
||||||
const parsed = submitSchema.safeParse({
|
const parsed = submitSchema.safeParse({
|
||||||
name: formData.get("name"),
|
name: formData.get("name"),
|
||||||
tags: rawTags,
|
tags: rawTags,
|
||||||
|
description: formData.get("description"),
|
||||||
qrBytesRaw: rawQrBytesRaw,
|
qrBytesRaw: rawQrBytesRaw,
|
||||||
image1: formData.get("image1"),
|
image1: formData.get("image1"),
|
||||||
image2: formData.get("image2"),
|
image2: formData.get("image2"),
|
||||||
|
|
@ -61,11 +63,12 @@ export async function POST(request: NextRequest) {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.errors[0].message }, 400);
|
if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.errors[0].message }, 400);
|
||||||
const { name: uncensoredName, tags: uncensoredTags, qrBytesRaw, image1, image2, image3 } = parsed.data;
|
const { name: uncensoredName, tags: uncensoredTags, description: uncensoredDescription, qrBytesRaw, image1, image2, image3 } = parsed.data;
|
||||||
|
|
||||||
// Censor potential inappropriate words
|
// Censor potential inappropriate words
|
||||||
const name = profanity.censor(uncensoredName);
|
const name = profanity.censor(uncensoredName);
|
||||||
const tags = uncensoredTags.map((t) => profanity.censor(t));
|
const tags = uncensoredTags.map((t) => profanity.censor(t));
|
||||||
|
const description = uncensoredDescription && profanity.censor(uncensoredDescription);
|
||||||
|
|
||||||
// Validate image files
|
// Validate image files
|
||||||
const images: File[] = [];
|
const images: File[] = [];
|
||||||
|
|
@ -97,6 +100,7 @@ export async function POST(request: NextRequest) {
|
||||||
userId: Number(session.user.id),
|
userId: Number(session.user.id),
|
||||||
name,
|
name,
|
||||||
tags,
|
tags,
|
||||||
|
description,
|
||||||
|
|
||||||
firstName: conversion.tomodachiLifeMii.firstName,
|
firstName: conversion.tomodachiLifeMii.firstName,
|
||||||
lastName: conversion.tomodachiLifeMii.lastName,
|
lastName: conversion.tomodachiLifeMii.lastName,
|
||||||
|
|
|
||||||
|
|
@ -200,6 +200,9 @@ export default async function MiiPage({ params }: Props) {
|
||||||
{mii.createdAt.toLocaleTimeString("en-GB", { timeZone: "UTC" })} UTC
|
{mii.createdAt.toLocaleTimeString("en-GB", { timeZone: "UTC" })} UTC
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Description */}
|
||||||
|
{mii.description && <p className="text-sm mt-2 ml-2 bg-white/50 p-3 rounded-lg border border-orange-200">{mii.description}</p>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Buttons */}
|
{/* Buttons */}
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@ export default function ReportMiiForm({ mii, likes }: Props) {
|
||||||
</label>
|
</label>
|
||||||
<textarea
|
<textarea
|
||||||
rows={3}
|
rows={3}
|
||||||
|
maxLength={256}
|
||||||
placeholder="Type notes here for the report..."
|
placeholder="Type notes here for the report..."
|
||||||
className="pill input !rounded-xl resize-none col-span-2"
|
className="pill input !rounded-xl resize-none col-span-2"
|
||||||
value={notes}
|
value={notes}
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ export default function ReportUserForm({ user }: Props) {
|
||||||
</label>
|
</label>
|
||||||
<textarea
|
<textarea
|
||||||
rows={3}
|
rows={3}
|
||||||
|
maxLength={256}
|
||||||
placeholder="Type notes here for the report..."
|
placeholder="Type notes here for the report..."
|
||||||
className="pill input !rounded-xl resize-none col-span-2"
|
className="pill input !rounded-xl resize-none col-span-2"
|
||||||
value={notes}
|
value={notes}
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ export default function SubmitForm() {
|
||||||
|
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
const [tags, setTags] = useState<string[]>([]);
|
const [tags, setTags] = useState<string[]>([]);
|
||||||
|
const [description, setDescription] = useState("");
|
||||||
const [qrBytesRaw, setQrBytesRaw] = useState<number[]>([]);
|
const [qrBytesRaw, setQrBytesRaw] = useState<number[]>([]);
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
|
|
@ -68,6 +69,7 @@ export default function SubmitForm() {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("name", name);
|
formData.append("name", name);
|
||||||
formData.append("tags", JSON.stringify(tags));
|
formData.append("tags", JSON.stringify(tags));
|
||||||
|
formData.append("description", description);
|
||||||
formData.append("qrBytesRaw", JSON.stringify(qrBytesRaw));
|
formData.append("qrBytesRaw", JSON.stringify(qrBytesRaw));
|
||||||
files.forEach((file, index) => {
|
files.forEach((file, index) => {
|
||||||
// image1, image2, etc.
|
// image1, image2, etc.
|
||||||
|
|
@ -190,6 +192,20 @@ export default function SubmitForm() {
|
||||||
<TagSelector tags={tags} setTags={setTags} />
|
<TagSelector tags={tags} setTags={setTags} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="w-full grid grid-cols-3 items-start">
|
||||||
|
<label htmlFor="reason-note" className="font-semibold py-2">
|
||||||
|
Description
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
rows={3}
|
||||||
|
maxLength={256}
|
||||||
|
placeholder="(optional) Type a description..."
|
||||||
|
className="pill input !rounded-xl resize-none col-span-2"
|
||||||
|
value={description}
|
||||||
|
onChange={(e) => setDescription(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Separator */}
|
{/* Separator */}
|
||||||
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mt-8 mb-2">
|
<div className="flex items-center gap-4 text-zinc-500 text-sm font-medium mt-8 mb-2">
|
||||||
<hr className="flex-grow border-zinc-300" />
|
<hr className="flex-grow border-zinc-300" />
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue