Commit 3145eb35 authored by wycers's avatar wycers
Browse files

create assignment with problems

parent c2b7e54a
Loading
Loading
Loading
Loading
+40 −0
Original line number Diff line number Diff line
<script lang="ts">
	import type { HTMLInputAttributes } from "svelte/elements";
	import { cn } from "$lib/utils";
	import type { InputEvents } from ".";

	type $$Props = HTMLInputAttributes & {
		ref?: HTMLInputElement
	};
	type $$Events = InputEvents;

	let className: $$Props["class"] = undefined;
	export let value: $$Props["value"] = undefined;
	export { className as class };
	export let ref: HTMLInputElement | null = null
</script>

<input
	class={cn(
		"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
		className
	)}
	type="number"
	bind:this={ref}
	bind:value
	on:blur
	on:change
	on:click
	on:focus
	on:focusin
	on:focusout
	on:keydown
	on:keypress
	on:keyup
	on:mouseover
	on:mouseenter
	on:mouseleave
	on:paste
	on:input
	{...$$restProps}
/>
 No newline at end of file
+32 −5
Original line number Diff line number Diff line
import { Prisma } from '@prisma/client';
import { db } from '.';

type CreateAssignmentSchema = {
@@ -7,6 +8,12 @@ type CreateAssignmentSchema = {
	description: string;
	startTime: string | Date;
	endTime: string | Date;
	problems: Array<{
		id: number;
		index: number;
		penalty: number;
		penaltyAfter: number;
	}>;
};

type UpdateAssignmentSchema = {
@@ -32,10 +39,30 @@ export const getAssignment = async (id: number) => {
	return assignments;
};

export const createAssignment = async ({ ...data }: CreateAssignmentSchema) => {
	const assignment = await db.assignment.create({
		data: { ...data }
export const createAssignment = async ({ problems, ...data }: CreateAssignmentSchema) => {
	const result = await db.$transaction(
		[
			db.assignment.create({
				data: {
					...data,
					problems: {
						connect: problems.map((p) => {
							return { id: p.id };
						})
					}
				}
			}),
			...problems.map(({ id, ...data }) => {
				return db.problem.update({
					where: { id: id },
					data
				});
			})
		],
		{
			isolationLevel: Prisma.TransactionIsolationLevel.Serializable // optional, default defined by database configuration
		}
	);

	return assignment;
	return result[0];
};
+101 −65
Original line number Diff line number Diff line
<script lang="ts" context="module">
	import { z } from 'zod';

	const languages = [
		{ label: 'English', value: 'en' },
		{ label: 'French', value: 'fr' },
		{ label: 'German', value: 'de' },
		{ label: 'Spanish', value: 'es' },
		{ label: 'Portuguese', value: 'pt' },
		{ label: 'Russian', value: 'ru' },
		{ label: 'Japanese', value: 'ja' },
		{ label: 'Korean', value: 'ko' },
		{ label: 'Chinese', value: 'zh' }
	] as const;

	type Language = (typeof languages)[number]['value'];
	import { number, z } from 'zod';

	export const accountFormSchema = z.object({
		classId: z.number(),
@@ -39,7 +25,17 @@
		endTime: z
			.string()
			.datetime()
			.refine((date) => (date === undefined ? false : true), 'Please select a valid date.')
			.refine((date) => (date === undefined ? false : true), 'Please select a valid date.'),
		problems: z
			.array(
				z.object({
					id: z.number(),
					index: z.number(),
					penalty: z.number().gte(0),
					penaltyAfter: z.number().gte(0)
				})
			)
			.default([])
	});

	export type AccountFormSchema = typeof accountFormSchema;
@@ -54,7 +50,9 @@
		type SuperValidated,
		type Infer,
		superForm,
		intProxy
		intProxy,
		arrayProxy,
		fieldProxy
	} from 'sveltekit-superforms';
	import { zodClient } from 'sveltekit-superforms/adapters';
	import * as Form from '$lib/components/ui/form';
@@ -62,7 +60,7 @@
	import * as Command from '$lib/components/ui/command';
	import { Calendar } from '$lib/components/ui/calendar';
	import { Input } from '$lib/components/ui/input';
	import { buttonVariants } from '$lib/components/ui/button';
	import { Button, buttonVariants } from '$lib/components/ui/button';
	import { cn } from '$lib/utils.js';
	import { browser, dev } from '$app/environment';
	import {
@@ -77,10 +75,14 @@
	import TimePicker from '$lib/components/ui/timer-picker/TimePicker.svelte';
	import moment from 'moment';
	import _ from 'lodash';
	import { tick } from 'svelte';
	import { writable, type Writable } from 'svelte/store';
	import NumberInput from '$lib/components/ui/input/numberInput.svelte';

	export let data: SuperValidated<Infer<AccountFormSchema>>;

	const form = superForm(data, {
		dataType: 'json',
		validators: zodClient(accountFormSchema)
	});
	const { form: formData, enhance, validate } = form;
@@ -110,7 +112,36 @@
			$formData.name = _.join(_.words(_.toLower($formData.title)), '-');
		}
	}
	const problemsProxy = writable<Array<{ id: Writable<string> }>>([]);

	function addProblem() {
		$formData.problems = [
			...$formData.problems,
			{
				id: 0,
				index: $formData.problems.length,
				penalty: 0,
				penaltyAfter: 0
			}
		];
		problemsProxy.update((x) => {
			x.push({
				id: intProxy(form, 'problems[0].id')
			});
			return x;
		});

		// tick().then(() => {
		// 	const urlInputs = Array.from(
		// 		document.querySelectorAll<HTMLElement>("#profile-form input[name='urls']")
		// 	);
		// 	const lastInput = urlInputs[urlInputs.length - 1];
		// 	lastInput && lastInput.focus();
		// });
	}
	const classId = intProxy(form, 'classId');
	let fuck = [intProxy(form, 'problems[0].id')];
	$: fuck = [intProxy(form, 'problems[0].id')];
</script>

<form method="POST" class="space-y-8" use:enhance>
@@ -228,53 +259,58 @@
		<Form.FieldErrors />
	</Form.Field>

	<!-- <Form.Field {form} name="language" class="flex flex-col">
		<Popover.Root>
	<div>
		<Form.Fieldset {form} name="problems">
			<Form.Legend>Problems</Form.Legend>
			{#each $formData.problems as _, i}
				<div class="flex flex-row rounded-t border">
					<Form.ElementField class="flex-1 px-2" {form} name="problems[{i}].id">
						<Form.Control let:attrs>
				<Form.Label>Language</Form.Label>
				<Popover.Trigger
					role="combobox"
					class={cn(
						buttonVariants({ variant: 'outline' }),
						'w-[200px] justify-between',
						!$formData.language && 'text-muted-foreground'
					)}
					{...attrs}
				>
					{languages.find((lang) => lang.value === $formData.language)?.label ||
						'Select a language'}
					<CaretSort class="ml-2 size-4 shrink-0 opacity-50" />
				</Popover.Trigger>
				<input hidden value={$formData.language} name={attrs.name} />
							<Form.Label>Problem #{i + 1} ID </Form.Label>
							<NumberInput {...attrs} bind:value={$formData.problems[i].id} />
						</Form.Control>
			<Popover.Content class="w-[200px] p-0">
				<Command.Root>
					<Command.Input placeholder="Search language..." />
					<Command.Empty>No language found.</Command.Empty>
					<Command.List>
						{#each languages as language}
							<Command.Item
								{...form}
								value={language.label}
								onSelect={() => {
									$formData.language = language.value;
									validate('language');
								}}
							>
								<Check
									class={cn(
										'mr-2 size-4',
										language.value === $formData.language ? 'opacity-100' : 'opacity-0'
									)}
								/>
								{language.label}
							</Command.Item>
						<Form.Description class={cn(i !== 0 && 'sr-only')}>
							The problem id
						</Form.Description>
						<Form.FieldErrors />
					</Form.ElementField>
					<Form.ElementField class="flex-1 px-2 hidden" {form} name="problems[{i}].index">
						<Form.Control let:attrs>
							<Form.Label>Index</Form.Label>
							<NumberInput {...attrs} bind:value={$formData.problems[i].index} />
						</Form.Control>
						<Form.Description class={cn(i !== 0 && 'sr-only')}>
							Index
						</Form.Description>
						<Form.FieldErrors />
					</Form.ElementField>
					<Form.ElementField class="flex-1 px-2" {form} name="problems[{i}].penaltyAfter">
						<Form.Control let:attrs>
							<Form.Label>Penalty After</Form.Label>
							<NumberInput {...attrs} bind:value={$formData.problems[i].penaltyAfter} />
						</Form.Control>
						<Form.Description class={cn(i !== 0 && 'sr-only')}>
							After the {$formData.problems[i].penaltyAfter} time of submission...
						</Form.Description>
						<Form.FieldErrors />
					</Form.ElementField>
					<Form.ElementField class="flex-1 px-2" {form} name="problems[{i}].penalty">
						<Form.Control let:attrs>
							<Form.Label>Penalty</Form.Label>
							<NumberInput {...attrs} bind:value={$formData.problems[i].penalty} />
						</Form.Control>
						<Form.FieldErrors />
						<Form.Description class={cn(i !== 0 && 'sr-only')}>
							User will receive a -{$formData.problems[i].penalty} penalty.
						</Form.Description>
					</Form.ElementField>
				</div>
			{/each}
					</Command.List>
				</Command.Root>
			</Popover.Content>
		</Popover.Root>
	</Form.Field> -->
		</Form.Fieldset>
		<Button type="button" variant="outline" size="sm" class="mt-2" on:click={addProblem}>
			Add URL
		</Button>
	</div>

	<Form.Button>Create Assignment</Form.Button>
</form>