Loggest thine Stuff
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

207 lines
6.9 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. <script lang="ts">
  2. import { getStores } from "$app/stores";
  3. import { sl3 } from "$lib/clients/sl3";
  4. import Modal from "$lib/components/common/Modal.svelte";
  5. import ModalBody from "$lib/components/common/ModalBody.svelte";
  6. import { getItemListContext } from "$lib/components/contexts/ItemListContext.svelte";
  7. import { getItemMultiListContext } from "$lib/components/contexts/ItemMultiListContext.svelte";
  8. import { getModalContext } from "$lib/components/contexts/ModalContext.svelte";
  9. import { getProjectContext } from "$lib/components/contexts/ProjectContext.svelte";
  10. import { getScopeContext } from "$lib/components/contexts/ScopeContext.svelte";
  11. import { getScopeListContext } from "$lib/components/contexts/ScopeListContext.svelte";
  12. import { getSprintListContext } from "$lib/components/contexts/SprintListContext.svelte";
  13. import AcquiredTimeInput from "$lib/components/controls/AcquiredTimeInput.svelte";
  14. import RequirementSelect from "$lib/components/controls/RequirementSelect.svelte";
  15. import StatInput from "$lib/components/controls/StatInput.svelte";
  16. import type Item from "$lib/models/item";
  17. import type { ItemInput } from "$lib/models/item";
  18. import type { Requirement } from "$lib/models/project";
  19. import type Scope from "$lib/models/scope";
  20. import { formatFormTime } from "$lib/utils/date";
  21. import { statDiff } from "$lib/utils/stat";
  22. const {currentModal, closeModal} = getModalContext();
  23. const {scope} = getScopeContext();
  24. const {scopes} = getScopeListContext();
  25. const {project, reloadProject} = getProjectContext();
  26. const {reloadItemList} = getItemListContext();
  27. const {reloadSprintList} = getSprintListContext();
  28. const {reloadItemLists} = getItemMultiListContext();
  29. const {page} = getStores();
  30. let item: ItemInput
  31. let itemId: number
  32. let scopeId: number
  33. let currentStats: ItemInput["stats"]
  34. let openedDate: Date
  35. let requirementName: string
  36. let op: string
  37. let initOnList: number[] = [];
  38. let error: string
  39. let loading: boolean
  40. let show: boolean
  41. $: switch ($currentModal.name) {
  42. case "item.create":
  43. initCreate($scope, $currentModal.requirement)
  44. break;
  45. case "item.edit": {
  46. const reqId = $currentModal.item.requirementId;
  47. initEdit($currentModal.item, $project.requirements.find(r => r.id === reqId), $scope)
  48. break;
  49. }
  50. default:
  51. loading = false;
  52. error = null;
  53. show = false;
  54. }
  55. function initCreate(scope: Scope, requirement?: Requirement) {
  56. let stats = requirement?.stats.map(s => ({statId: s.id, required: 0, acquired: 0}));
  57. if (stats == null) {
  58. stats = scope.stats.map(s => ({statId: s.id, required: 0, acquired: 0}))
  59. } else {
  60. initOnList = requirement.stats.filter(s => s.required > 0).map(s => s.id);
  61. }
  62. item = {
  63. name: "",
  64. description: "",
  65. requirementId: requirement?.id,
  66. stats: stats,
  67. acquiredTime: null,
  68. scheduledDate: null,
  69. }
  70. op = "Create"
  71. scopeId = scope.id;
  72. openedDate = new Date();
  73. requirementName = requirement?.name;
  74. show = true;
  75. }
  76. function initEdit(current: Item, requirement?: Requirement, scope?: Scope) {
  77. const req = $project.requirements?.find(r => r.id === current.requirementId);
  78. let ctxStats = requirement?.stats.map(s => ({statId: s.id, required: 0, acquired: 0}));
  79. if (ctxStats == null || ctxStats.length === 0) {
  80. let actualScope = scope;
  81. if (actualScope.id !== current.scopeId && $scopes?.length > 0) {
  82. actualScope = $scopes.find(s => s.id === current.scopeId)
  83. }
  84. ctxStats = actualScope.stats.map(s => ({statId: s.id, required: 0, acquired: 0}));
  85. }
  86. const inputStats = current.stats.map(s => ({statId: s.id, acquired: s.acquired, required: s.required}));
  87. item = {
  88. name: current.name,
  89. description: current.description,
  90. requirementId: current.requirementId,
  91. stats: ctxStats.map(s => inputStats.find(s2 => s2.statId === s.statId) || s),
  92. acquiredTime: formatFormTime(current.acquiredTime),
  93. scheduledDate: current.scheduledDate,
  94. };
  95. itemId = current.id;
  96. scopeId = current.scopeId;
  97. currentStats = [...item.stats];
  98. op = "Edit"
  99. openedDate = new Date();
  100. requirementName = current.requirement?.name;
  101. show = true;
  102. }
  103. async function submit() {
  104. error = null;
  105. loading = true;
  106. const submission: ItemInput = {
  107. ...item,
  108. acquiredTime: item.acquiredTime ? new Date(item.acquiredTime).toISOString() : void(0),
  109. stats: item.stats.filter(s => s.required > 0),
  110. }
  111. try {
  112. switch (op) {
  113. case "Create":
  114. if (!!submission.acquiredTime) {
  115. for (const stat of submission.stats) {
  116. stat.acquired = stat.required
  117. }
  118. } else {
  119. for (const stat of submission.stats) {
  120. stat.acquired = 0
  121. }
  122. }
  123. await sl3(fetch, $page.stuff.idToken).createItem(scopeId, submission);
  124. break;
  125. case "Edit":
  126. if (!submission.acquiredTime) {
  127. for (const stat of submission.stats) {
  128. stat.acquired = 0
  129. }
  130. submission.clearAcquiredTime = true;
  131. }
  132. submission.stats = statDiff(currentStats, submission.stats)
  133. await sl3(fetch, $page.stuff.idToken).updateItem(scopeId, itemId, submission);
  134. break;
  135. }
  136. // Wait for project reload if it's updating a project
  137. if (item.requirementId != null) {
  138. await reloadProject();
  139. }
  140. await reloadItemList();
  141. await reloadSprintList();
  142. reloadItemLists();
  143. closeModal();
  144. } catch(err) {
  145. if (err.statusCode != null) {
  146. error = err.statusMessage;
  147. } else {
  148. error = err
  149. }
  150. } finally {
  151. loading = false;
  152. }
  153. }
  154. </script>
  155. <form on:submit|preventDefault={submit}>
  156. <Modal wide closable show={show} verb={op} noun="Item" disabled={loading} error={error}>
  157. <ModalBody>
  158. <label for="name">Name</label>
  159. <input name="name" type="text" bind:value={item.name} />
  160. <label for="acquiredTime">Acquired</label>
  161. <AcquiredTimeInput openDate={openedDate} bind:value={item.acquiredTime} />
  162. <label for="description">Description</label>
  163. <textarea name="description" bind:value={item.description} />
  164. </ModalBody>
  165. <ModalBody>
  166. {#if requirementName != null}
  167. <label for="req">Project Requirement</label>
  168. {#if $project.id != null}
  169. <RequirementSelect disabled={op === "Create"} requirements={$project.requirements} bind:value={item.requirementId} />
  170. {:else}
  171. <input disabled name="req" type="text" value={requirementName} />
  172. {/if}
  173. {/if}
  174. <label for="stats">Stats</label>
  175. <StatInput
  176. zeroDeletes showRequired
  177. overrideScopeId={scopeId}
  178. initOnList={initOnList}
  179. showAcquired={op === "Edit" && !!item.acquiredTime}
  180. hideUnseen={!!item.requirementId}
  181. bind:value={item.stats}
  182. />
  183. </ModalBody>
  184. </Modal>
  185. </form>