style: IDK WHAT IUS FUCKING ON
This commit is contained in:
@@ -201,7 +201,7 @@ export default function FormEditorClient({ form, initialQuestions }: FormEditorC
|
|||||||
});
|
});
|
||||||
router.refresh();
|
router.refresh();
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
toast.error(getErrorMessage(err, "Could not delete the question."));
|
toast.error(getErrorMessage(err, "Could not remove the question."));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -407,19 +407,53 @@ export default function FormEditorClient({ form, initialQuestions }: FormEditorC
|
|||||||
<AccordionItem value={q.id} className="border-0">
|
<AccordionItem value={q.id} className="border-0">
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader className="pl-12">
|
<CardHeader className="pl-12">
|
||||||
<AccordionTrigger className="py-0 hover:no-underline">
|
<div className="relative flex items-center">
|
||||||
<div className="min-w-0 text-left">
|
<div className="min-w-0 flex-1">
|
||||||
<CardTitle className="truncate text-base">
|
<AccordionTrigger className="w-full min-w-0 py-0 pr-32 hover:no-underline [&_[data-slot=accordion-trigger-icon]]:absolute [&_[data-slot=accordion-trigger-icon]]:right-0 [&_[data-slot=accordion-trigger-icon]]:top-1/2 [&_[data-slot=accordion-trigger-icon]]:-translate-y-1/2">
|
||||||
{stripHtml(q.label) || `Untitled question ${index + 1}`}
|
<div className="min-w-0 text-left">
|
||||||
</CardTitle>
|
<CardTitle className="truncate text-base">
|
||||||
<CardDescription>
|
{stripHtml(q.label) || `Untitled question ${index + 1}`}
|
||||||
Question {index + 1} · {questionTypeLabel(q.type)}
|
</CardTitle>
|
||||||
{q.required ? " · Required" : ""}
|
<CardDescription>
|
||||||
</CardDescription>
|
Question {index + 1} · {questionTypeLabel(q.type)}
|
||||||
|
{q.required ? " · Required" : ""}
|
||||||
|
</CardDescription>
|
||||||
|
</div>
|
||||||
|
</AccordionTrigger>
|
||||||
</div>
|
</div>
|
||||||
</AccordionTrigger>
|
<AlertDialog>
|
||||||
|
<AlertDialogTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
className="absolute right-8 top-1/2 -translate-y-1/2 text-destructive"
|
||||||
|
aria-label={`Remove question ${index + 1}`}
|
||||||
|
>
|
||||||
|
<Trash data-icon="inline-start" />
|
||||||
|
Remove
|
||||||
|
</Button>
|
||||||
|
</AlertDialogTrigger>
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>Remove question {index + 1}?</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>
|
||||||
|
This permanently removes the question and its stored answers.
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel>Keep question</AlertDialogCancel>
|
||||||
|
<AlertDialogAction
|
||||||
|
variant="destructive"
|
||||||
|
onClick={() => void handleDeleteQuestion(q.id)}
|
||||||
|
>
|
||||||
|
Remove question
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<AccordionContent>
|
<AccordionContent className="h-auto">
|
||||||
<CardContent className="flex flex-col gap-4 pt-0">
|
<CardContent className="flex flex-col gap-4 pt-0">
|
||||||
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-4">
|
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-4">
|
||||||
<div className="flex-1 w-full">
|
<div className="flex-1 w-full">
|
||||||
@@ -431,23 +465,6 @@ export default function FormEditorClient({ form, initialQuestions }: FormEditorC
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2 self-end sm:self-auto">
|
<div className="flex items-center gap-2 self-end sm:self-auto">
|
||||||
<Select
|
|
||||||
value={q.type}
|
|
||||||
onValueChange={(val) => handleUpdateQuestion(q.id, { type: val as Question["type"] })}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="w-36">
|
|
||||||
<SelectValue />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectGroup>
|
|
||||||
<SelectItem value="text">Short answer</SelectItem>
|
|
||||||
<SelectItem value="textarea">Paragraph</SelectItem>
|
|
||||||
<SelectItem value="radio">Choose one</SelectItem>
|
|
||||||
<SelectItem value="checkbox">Choose multiple</SelectItem>
|
|
||||||
</SelectGroup>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
|
|
||||||
<div className="flex items-center gap-1 border rounded-md p-1">
|
<div className="flex items-center gap-1 border rounded-md p-1">
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@@ -470,6 +487,23 @@ export default function FormEditorClient({ form, initialQuestions }: FormEditorC
|
|||||||
<ArrowDown />
|
<ArrowDown />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Select
|
||||||
|
value={q.type}
|
||||||
|
onValueChange={(val) => handleUpdateQuestion(q.id, { type: val as Question["type"] })}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="w-36">
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectGroup>
|
||||||
|
<SelectItem value="text">Short answer</SelectItem>
|
||||||
|
<SelectItem value="textarea">Paragraph</SelectItem>
|
||||||
|
<SelectItem value="radio">Choose one</SelectItem>
|
||||||
|
<SelectItem value="checkbox">Choose multiple</SelectItem>
|
||||||
|
</SelectGroup>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -570,51 +604,18 @@ export default function FormEditorClient({ form, initialQuestions }: FormEditorC
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex justify-between items-center pt-2 border-t border-border">
|
{(q.type === "radio" || q.type === "checkbox") && (
|
||||||
<div className="flex items-center flex-wrap gap-6">
|
<div className="flex items-center gap-2 border-t border-border pt-2">
|
||||||
{(q.type === "radio" || q.type === "checkbox") && (
|
<Switch
|
||||||
<div className="flex items-center gap-2">
|
id={`allowOther-${q.id}`}
|
||||||
<Switch
|
checked={q.allowOther}
|
||||||
id={`allowOther-${q.id}`}
|
onCheckedChange={(checked) => handleUpdateQuestion(q.id, { allowOther: checked })}
|
||||||
checked={q.allowOther}
|
/>
|
||||||
onCheckedChange={(checked) => handleUpdateQuestion(q.id, { allowOther: checked })}
|
<Label htmlFor={`allowOther-${q.id}`} className="text-sm font-normal text-muted-foreground">
|
||||||
/>
|
Add 'Other' option
|
||||||
<Label htmlFor={`allowOther-${q.id}`} className="text-sm font-normal text-muted-foreground">
|
</Label>
|
||||||
Add 'Other' option
|
|
||||||
</Label>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<AlertDialog>
|
)}
|
||||||
<AlertDialogTrigger asChild>
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="icon"
|
|
||||||
className="text-destructive hover:bg-destructive/10"
|
|
||||||
aria-label={`Delete question ${index + 1}`}
|
|
||||||
>
|
|
||||||
<Trash />
|
|
||||||
</Button>
|
|
||||||
</AlertDialogTrigger>
|
|
||||||
<AlertDialogContent>
|
|
||||||
<AlertDialogHeader>
|
|
||||||
<AlertDialogTitle>Delete question {index + 1}?</AlertDialogTitle>
|
|
||||||
<AlertDialogDescription>
|
|
||||||
This permanently removes the question and its stored answers.
|
|
||||||
</AlertDialogDescription>
|
|
||||||
</AlertDialogHeader>
|
|
||||||
<AlertDialogFooter>
|
|
||||||
<AlertDialogCancel>Keep question</AlertDialogCancel>
|
|
||||||
<AlertDialogAction
|
|
||||||
variant="destructive"
|
|
||||||
onClick={() => void handleDeleteQuestion(q.id)}
|
|
||||||
>
|
|
||||||
Delete question
|
|
||||||
</AlertDialogAction>
|
|
||||||
</AlertDialogFooter>
|
|
||||||
</AlertDialogContent>
|
|
||||||
</AlertDialog>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</AccordionContent>
|
</AccordionContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -106,9 +106,12 @@ export default async function ResultsListPage({
|
|||||||
Array.isArray(submission.editHistory) &&
|
Array.isArray(submission.editHistory) &&
|
||||||
submission.editHistory.length > 0;
|
submission.editHistory.length > 0;
|
||||||
return (
|
return (
|
||||||
<TableRow key={submission.id}>
|
<TableRow key={submission.id} className="relative cursor-pointer">
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Link href={detailHref} className="font-medium hover:underline">
|
<Link
|
||||||
|
href={detailHref}
|
||||||
|
className="font-medium after:absolute after:inset-0 focus-visible:outline-none focus-visible:after:ring-2 focus-visible:after:ring-ring focus-visible:after:ring-inset"
|
||||||
|
>
|
||||||
{submission.userName ||
|
{submission.userName ||
|
||||||
submission.userDiscordId ||
|
submission.userDiscordId ||
|
||||||
"Anonymous"}
|
"Anonymous"}
|
||||||
@@ -125,7 +128,7 @@ export default async function ResultsListPage({
|
|||||||
{edited ? "Edited" : "Original"}
|
{edited ? "Edited" : "Original"}
|
||||||
</Badge>
|
</Badge>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="text-right">
|
<TableCell className="relative z-10 text-right">
|
||||||
<DeleteSubmissionButton id={submission.id} compact />
|
<DeleteSubmissionButton id={submission.id} compact />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@@ -140,10 +143,16 @@ export default async function ResultsListPage({
|
|||||||
{rows.map((submission) => {
|
{rows.map((submission) => {
|
||||||
const detailHref = `/admin/form/${id}/result/${submission.id}${listQuery ? `?return=${encodeURIComponent(listQuery)}` : ""}`;
|
const detailHref = `/admin/form/${id}/result/${submission.id}${listQuery ? `?return=${encodeURIComponent(listQuery)}` : ""}`;
|
||||||
return (
|
return (
|
||||||
<Card key={submission.id}>
|
<Card
|
||||||
|
key={submission.id}
|
||||||
|
className="relative transition-colors hover:bg-muted/50"
|
||||||
|
>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="text-base">
|
<CardTitle className="text-base">
|
||||||
<Link href={detailHref}>
|
<Link
|
||||||
|
href={detailHref}
|
||||||
|
className="after:absolute after:inset-0 focus-visible:outline-none focus-visible:after:ring-2 focus-visible:after:ring-ring focus-visible:after:ring-inset"
|
||||||
|
>
|
||||||
{submission.userName ||
|
{submission.userName ||
|
||||||
submission.userDiscordId ||
|
submission.userDiscordId ||
|
||||||
"Anonymous"}
|
"Anonymous"}
|
||||||
@@ -154,7 +163,9 @@ export default async function ResultsListPage({
|
|||||||
</CardDescription>
|
</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="flex justify-end">
|
<CardContent className="flex justify-end">
|
||||||
<DeleteSubmissionButton id={submission.id} compact />
|
<div className="relative z-10">
|
||||||
|
<DeleteSubmissionButton id={submission.id} compact />
|
||||||
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,9 +2,6 @@ import type { NextConfig } from "next";
|
|||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
serverExternalPackages: ["bun"],
|
serverExternalPackages: ["bun"],
|
||||||
experimental: {
|
|
||||||
turbopackFileSystemCacheForBuild: true,
|
|
||||||
},
|
|
||||||
turbopack: {
|
turbopack: {
|
||||||
root: process.cwd(),
|
root: process.cwd(),
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user