|
|
<script lang="ts"> import { getStores } from "$app/stores";
import { sl3 } from "$lib/clients/sl3"; import Modal from "$lib/components/common/Modal.svelte"; import ModalBody from "$lib/components/common/ModalBody.svelte"; import { getModalContext } from "$lib/components/contexts/ModalContext.svelte"; import { getScopeContext } from "$lib/components/contexts/ScopeContext.svelte"; import { getSprintListContext } from "$lib/components/contexts/SprintListContext.svelte"; import PartInput from "$lib/components/controls/PartInput.svelte"; import SprintKindSelect from "$lib/components/controls/SprintKindSelect.svelte"; import TagInput from "$lib/components/controls/TagInput.svelte"; import TimeRangeInput from "$lib/components/controls/TimeRangeInput.svelte"; import Checkbox from "$lib/components/layout/Checkbox.svelte"; import type Scope from "$lib/models/scope"; import type Sprint from "$lib/models/sprint"; import { SprintKind, type SprintInput, type SprintInputPart } from "$lib/models/sprint"; import { formatFormTime } from "$lib/utils/date"; import { partsDiff } from "$lib/utils/sprint";
const {currentModal, closeModal} = getModalContext(); const {scope} = getScopeContext(); const {reloadSprintList} = getSprintListContext(); const {page} = getStores();
let sprint: SprintInput let sprintId: number let scopeId: number let oldParts: SprintInputPart[] let intervalName: string; let openedDate: Date let op: string let error: string let loading: boolean let show: boolean
$: switch ($currentModal.name) { case "sprint.create": initCreate($scope) break; case "sprint.edit": initEdit($currentModal.sprint) break;
default: loading = false; error = null; show = false; }
function initCreate(scope: Scope) { sprint = { name: "", description: "", fromTime: "", toTime: "", kind: SprintKind.Stats, aggregateName: "", aggregateRequired: 0, isCoarse: false, isTimed: false, isUnweighted: false, parts: [], tags: [], } intervalName = "this_month"; scopeId = scope.id;
op = "Create" openedDate = new Date(); show = true; }
function initEdit(current: Sprint) { sprint = { name: current.name, description: current.description, fromTime: formatFormTime(current.fromTime), toTime: formatFormTime(current.toTime), kind: current.kind, aggregateName: current.aggregateName, aggregateRequired: current.aggregateRequired, isCoarse: current.isCoarse, isTimed: current.isTimed, isUnweighted: current.isUnweighted, tags: [...(current.tags||[])], }; sprintId = current.id; scopeId = current.scopeId; intervalName = "specific_dates";
if (sprint.kind === SprintKind.Stats) { sprint.parts = current.progress.map(p => ({partId: p.id, required: p.required})); } else { sprint.parts = current.partIds.map(p => ({partId: p, required: 0})); } oldParts = [...sprint.parts];
op = "Edit" openedDate = new Date(); show = true; }
async function submit() { error = null; loading = true;
const submission: SprintInput = { ...sprint, fromTime: new Date(sprint.fromTime).toISOString(), toTime: new Date(sprint.toTime).toISOString(), }
try { switch (op) { case "Create": await sl3(fetch).createSprint(scopeId, submission); break; case "Edit": await sl3(fetch).updateSprint(scopeId, sprintId, submission); const {added, removed} = partsDiff(oldParts, submission.parts) for (const part of added) { await sl3(fetch).upsertSprintPart(scopeId, sprintId, part).catch(() => {}); } for (const part of removed) { await sl3(fetch).deleteSprintPart(scopeId, sprintId, part).catch(() => {}); }
break; }
await reloadSprintList();
closeModal(); } catch(err) { if (err.statusCode != null) { error = err.statusMessage; } else { error = err }
} finally { loading = false; } } </script>
<form on:submit|preventDefault={submit}> <Modal wide closable show={show} verb={op} noun="sprint" disabled={loading} error={error}> <ModalBody> <label for="name">Name</label> <input name="name" type="text" bind:value={sprint.name} /> <label for="description">Description</label> <textarea name="description" bind:value={sprint.description} /> <label for="time">Time</label> <TimeRangeInput openDate={openedDate} bind:from={sprint.fromTime} bind:to={sprint.toTime} bind:intervalName={intervalName} /> <label for="aggregateName">Aggregate Name</label> <input name="aggregateName" type="text" bind:value={sprint.aggregateName} /> <label for="tags">Tags</label> <TagInput exclaimMode bind:value={sprint.tags} /> {#if sprint.kind != SprintKind.Items} <label for="aggregateValue">Aggregate Goal</label> <input name="aggregateValue" type="number" bind:value={sprint.aggregateRequired} /> {/if} <Checkbox bind:checked={sprint.isTimed} label="Sprint is timed" /> <Checkbox bind:checked={sprint.isCoarse} label="Show only aggregate" /> <Checkbox bind:checked={sprint.isUnweighted} label="Aggregate is unweighted" /> </ModalBody> <ModalBody> <label for="kind">Kind</label> <SprintKindSelect disabled={op === "Edit"} bind:kind={sprint.kind} /> <label for="parts">Parts</label> <PartInput bind:value={sprint.parts} kind={sprint.kind} scopeId={scopeId} /> </ModalBody> </Modal> </form>
|