diff --git a/db.kv b/db.kv new file mode 100644 index 0000000..9a47220 Binary files /dev/null and b/db.kv differ diff --git a/db.kv-shm b/db.kv-shm new file mode 100644 index 0000000..a1eba0a Binary files /dev/null and b/db.kv-shm differ diff --git a/db.kv-wal b/db.kv-wal new file mode 100644 index 0000000..a90e8b2 Binary files /dev/null and b/db.kv-wal differ diff --git a/package-lock.json b/package-lock.json index 224ca26..7d2d92e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,11 +11,13 @@ "@deno/kv": "^0.7.0", "discord-api-types": "^0.37.67", "export-to-csv": "^1.2.2", + "sortablejs": "^1.15.2", "ulid": "^2.3.0" }, "devDependencies": { "@sveltejs/adapter-auto": "^2.0.0", "@sveltejs/kit": "^1.20.4", + "@types/sortablejs": "^1.15.8", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "eslint": "^8.28.0", @@ -786,6 +788,12 @@ "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", "dev": true }, + "node_modules/@types/sortablejs": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@types/sortablejs/-/sortablejs-1.15.8.tgz", + "integrity": "sha512-b79830lW+RZfwaztgs1aVPgbasJ8e7AXtZYHTELNXZPsERt4ymJdjV4OccDbHQAvHrCcFpbF78jkm0R6h/pZVg==", + "dev": true + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.8.0.tgz", @@ -2748,6 +2756,11 @@ "sorcery": "bin/sorcery" } }, + "node_modules/sortablejs": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.2.tgz", + "integrity": "sha512-FJF5jgdfvoKn1MAKSdGs33bIqLi3LmsgVTliuX6iITj834F+JRQZN90Z93yql8h0K2t0RwDPBmxwlbZfDcxNZA==" + }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -3656,6 +3669,12 @@ "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", "dev": true }, + "@types/sortablejs": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@types/sortablejs/-/sortablejs-1.15.8.tgz", + "integrity": "sha512-b79830lW+RZfwaztgs1aVPgbasJ8e7AXtZYHTELNXZPsERt4ymJdjV4OccDbHQAvHrCcFpbF78jkm0R6h/pZVg==", + "dev": true + }, "@typescript-eslint/eslint-plugin": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.8.0.tgz", @@ -5018,6 +5037,11 @@ "sander": "^0.5.0" } }, + "sortablejs": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.2.tgz", + "integrity": "sha512-FJF5jgdfvoKn1MAKSdGs33bIqLi3LmsgVTliuX6iITj834F+JRQZN90Z93yql8h0K2t0RwDPBmxwlbZfDcxNZA==" + }, "source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", diff --git a/package.json b/package.json index a5541ec..1c3c58c 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "devDependencies": { "@sveltejs/adapter-auto": "^2.0.0", "@sveltejs/kit": "^1.20.4", + "@types/sortablejs": "^1.15.8", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "eslint": "^8.28.0", @@ -33,6 +34,7 @@ "@deno/kv": "^0.7.0", "discord-api-types": "^0.37.67", "export-to-csv": "^1.2.2", + "sortablejs": "^1.15.2", "ulid": "^2.3.0" } } diff --git a/src/lib/components/form/form.svelte b/src/lib/components/form/form.svelte index cf1889d..e41aba6 100644 --- a/src/lib/components/form/form.svelte +++ b/src/lib/components/form/form.svelte @@ -1,11 +1,11 @@
@@ -65,9 +76,8 @@ bind:value={value.questions.shuffled} /> - - - + + diff --git a/src/lib/components/form_editor/question_input_editor/question_input_editor.svelte b/src/lib/components/form_editor/question_input_editor/question_input_editor.svelte index f40e9bf..08d6d2c 100644 --- a/src/lib/components/form_editor/question_input_editor/question_input_editor.svelte +++ b/src/lib/components/form_editor/question_input_editor/question_input_editor.svelte @@ -1,11 +1,52 @@ + + +
+ {#if data.type === QuestionType.BOOLEAN} + + {:else if data.type === QuestionType.COLOR} + + {:else if data.type === QuestionType.NUMBER} + + {:else if data.type === QuestionType.TEXT} + + {:else if data.type === QuestionType.TEXTAREA} + + {:else if data.type === QuestionType.DATE} + + {:else if data.type === QuestionType.DATETIME} + + {:else if data.type === QuestionType.TIME} + + {:else if data.type === QuestionType.RADIO_GROUP} + + {:else if data.type === QuestionType.AVAILABILITY} + + {:else if data.type === QuestionType.SELECT} + + {/if} +
+ + diff --git a/src/lib/components/form_editor/question_list_editor/add_item.svelte b/src/lib/components/form_editor/question_list_editor/add_item.svelte index b52fea6..9fbd6ce 100644 --- a/src/lib/components/form_editor/question_list_editor/add_item.svelte +++ b/src/lib/components/form_editor/question_list_editor/add_item.svelte @@ -1,14 +1,15 @@ + + + + + diff --git a/src/lib/components/form_editor/question_list_editor/question_list_editor.svelte b/src/lib/components/form_editor/question_list_editor/question_list_editor.svelte index c3714d8..b4df14e 100644 --- a/src/lib/components/form_editor/question_list_editor/question_list_editor.svelte +++ b/src/lib/components/form_editor/question_list_editor/question_list_editor.svelte @@ -10,12 +10,12 @@ export let value: QuestionList; - +/> --> diff --git a/src/lib/components/list_input/list_input.svelte b/src/lib/components/list_input/list_input.svelte index c65a1f7..a6ad3b6 100644 --- a/src/lib/components/list_input/list_input.svelte +++ b/src/lib/components/list_input/list_input.svelte @@ -1,30 +1,89 @@ -
- {#each value as item, i} -
- - deleteItem(i)} /> -
- {:else} - {#if components.emptySection} - - {/if} - {/each} - addItem(item)} /> -
+{#if value.length > 0} +
    + {#each value as item, i} +
  • +
    + + + + + + + + {#if item.content} + {item.content} + {:else} + Untitled + {/if} + + {#if item.value} + {item.value} + {:else} + No value found + {/if} + + {item.type} + + + deleteItem(i)} /> +
    +
  • + {/each} +
+{:else if components.emptySection} + +{/if} + + addItem(item)} /> + + diff --git a/src/lib/components/list_input/list_input.ts b/src/lib/components/list_input/list_input.ts index 259d0d0..db841ed 100644 --- a/src/lib/components/list_input/list_input.ts +++ b/src/lib/components/list_input/list_input.ts @@ -1,6 +1,6 @@ import type { ComponentType, SvelteComponent } from 'svelte'; -export type ItemProps = object; +export type ItemProps = Record; export interface AddItemProps { addAction(item: ItemProps): void; diff --git a/src/lib/components/question_input/question_input.svelte b/src/lib/components/question_input/question_input.svelte index e5bf2bd..e28f718 100644 --- a/src/lib/components/question_input/question_input.svelte +++ b/src/lib/components/question_input/question_input.svelte @@ -11,6 +11,7 @@ import TextareaQuestionInput from '$lib/components/questions/textarea/textarea_question_input.svelte'; import TimeQuestionInput from '$lib/components/questions/time/time_question_input.svelte'; import SelectQuestionInput from '$lib/components/questions/select/select_question_input.svelte'; + import TimezoneQuestionInput from '../questions/timezone/timezone_question_input.svelte';
@@ -36,6 +37,8 @@ {:else if $$props.type === QuestionType.SELECT} + {:else if $$props.type === QuestionType.TIMEZONE} + {/if}
diff --git a/src/lib/components/questions/availability/availability_question_input.svelte b/src/lib/components/questions/availability/availability_question_input.svelte index 7203350..76bc343 100644 --- a/src/lib/components/questions/availability/availability_question_input.svelte +++ b/src/lib/components/questions/availability/availability_question_input.svelte @@ -1,13 +1,18 @@
{data.content}
{#each Array.from({ length: data.maxDatetimeRanges ?? 1 }, (_, i) => i) as i} +
+ import type { AvailablityQuestion } from '$lib/form'; + import { QuestionType } from '$lib/form'; + import ListInput from '$lib/components/list_input/list_input.svelte'; + import TextQuestionInput from '../text/text_question_input.svelte'; + import DeleteItem from '$lib/components/form_editor/question_list_editor/delete_item.svelte'; + import BaseEditor from '../base/base_editor.svelte'; + import TextQuestionInputEditor from '../text/text_question_input_editor.svelte'; + import AvailabilityQuestionInput from './availability_question_input.svelte'; + import DatetimeQuestionInput from '../datetime/datetime_question_input.svelte'; + import AddItem from '$lib/components/form_editor/question_list_editor/add_item.svelte'; + // import AvailabilityAddItem from './availability_add_item.svelte'; + + export var data = $$props as AvailablityQuestion; + + + + +
+ Enter Min Start Date Time + +
+ +
+ Enter Max End Date Time + +
+ +
+ Enter Max Date Ranges + +
+ + + + + +
diff --git a/src/lib/components/questions/base/base_editor.svelte b/src/lib/components/questions/base/base_editor.svelte new file mode 100644 index 0000000..f973a73 --- /dev/null +++ b/src/lib/components/questions/base/base_editor.svelte @@ -0,0 +1,160 @@ + + + +
+ + +
+
+ Question Title + +
+ +
+ Internal Question + +
+ +
+ Question Required + +
+ + + +
+ + + +
+ +
+
+ + diff --git a/src/lib/components/questions/base/choice_editor.svelte b/src/lib/components/questions/base/choice_editor.svelte new file mode 100644 index 0000000..f5cd301 --- /dev/null +++ b/src/lib/components/questions/base/choice_editor.svelte @@ -0,0 +1,20 @@ + + +
+ Choice Content + +
+ +
+ Choice internal value + +
diff --git a/src/lib/components/questions/boolean/boolean_question_input.svelte b/src/lib/components/questions/boolean/boolean_question_input.svelte index dd7c933..50a3e63 100644 --- a/src/lib/components/questions/boolean/boolean_question_input.svelte +++ b/src/lib/components/questions/boolean/boolean_question_input.svelte @@ -1,7 +1,7 @@
diff --git a/src/lib/components/questions/boolean/boolean_question_input_editor.svelte b/src/lib/components/questions/boolean/boolean_question_input_editor.svelte index e69de29..f4f2af3 100644 --- a/src/lib/components/questions/boolean/boolean_question_input_editor.svelte +++ b/src/lib/components/questions/boolean/boolean_question_input_editor.svelte @@ -0,0 +1,42 @@ + + + +
+ Choose a Style + +
+ +
+ +
+
+
diff --git a/src/lib/components/questions/color/color_question_input.svelte b/src/lib/components/questions/color/color_question_input.svelte index 427ef42..c218860 100644 --- a/src/lib/components/questions/color/color_question_input.svelte +++ b/src/lib/components/questions/color/color_question_input.svelte @@ -1,10 +1,10 @@
{data.content} - +
diff --git a/src/lib/components/questions/color/color_question_input_editor.svelte b/src/lib/components/questions/color/color_question_input_editor.svelte index e69de29..2de6841 100644 --- a/src/lib/components/questions/color/color_question_input_editor.svelte +++ b/src/lib/components/questions/color/color_question_input_editor.svelte @@ -0,0 +1,23 @@ + + + + +
+ Default Color + +
+ +
+ +
+
+
diff --git a/src/lib/components/questions/date/date_question_input.svelte b/src/lib/components/questions/date/date_question_input.svelte index 89b66cd..02a25a9 100644 --- a/src/lib/components/questions/date/date_question_input.svelte +++ b/src/lib/components/questions/date/date_question_input.svelte @@ -1,7 +1,7 @@
@@ -12,6 +12,6 @@ required={data.required} min={data.min} max={data.max} - value={data.value} + bind:value={data.value} />
diff --git a/src/lib/components/questions/date/date_question_input_editor.svelte b/src/lib/components/questions/date/date_question_input_editor.svelte index e69de29..7d01530 100644 --- a/src/lib/components/questions/date/date_question_input_editor.svelte +++ b/src/lib/components/questions/date/date_question_input_editor.svelte @@ -0,0 +1,34 @@ + + + +
+ Min Date + +
+
+ Max Date + +
+
+ Default Date + +
+ +
+ +
+
+
diff --git a/src/lib/components/questions/datetime/datetime_question_input.svelte b/src/lib/components/questions/datetime/datetime_question_input.svelte index 49e0182..c572199 100644 --- a/src/lib/components/questions/datetime/datetime_question_input.svelte +++ b/src/lib/components/questions/datetime/datetime_question_input.svelte @@ -1,7 +1,7 @@
@@ -10,7 +10,7 @@ name={data.name} type="datetime-local" required={data.required} - value={data.value} + bind:value={data.value} min={data.min} max={data.max} /> diff --git a/src/lib/components/questions/datetime/datetime_question_input_editor.svelte b/src/lib/components/questions/datetime/datetime_question_input_editor.svelte index e69de29..57e3fd8 100644 --- a/src/lib/components/questions/datetime/datetime_question_input_editor.svelte +++ b/src/lib/components/questions/datetime/datetime_question_input_editor.svelte @@ -0,0 +1,34 @@ + + + +
+ Min Date/Time + +
+
+ Max Date/Time + +
+
+ Default Date/Time + +
+ +
+ +
+
+
diff --git a/src/lib/components/questions/number/number_question_input.svelte b/src/lib/components/questions/number/number_question_input.svelte index 605ee60..d09f2be 100644 --- a/src/lib/components/questions/number/number_question_input.svelte +++ b/src/lib/components/questions/number/number_question_input.svelte @@ -1,7 +1,7 @@
diff --git a/src/lib/components/questions/number/number_question_input_editor.svelte b/src/lib/components/questions/number/number_question_input_editor.svelte index e69de29..10a3dfe 100644 --- a/src/lib/components/questions/number/number_question_input_editor.svelte +++ b/src/lib/components/questions/number/number_question_input_editor.svelte @@ -0,0 +1,37 @@ + + + + +
+ min + +
+
+ max + +
+ +
+ step + +
+ +
+ Defualt value + +
+
+ placeholder + +
+ +
+ +
+
+
diff --git a/src/lib/components/questions/radio_group/radio_group_add_item.svelte b/src/lib/components/questions/radio_group/radio_group_add_item.svelte new file mode 100644 index 0000000..f8472b7 --- /dev/null +++ b/src/lib/components/questions/radio_group/radio_group_add_item.svelte @@ -0,0 +1,20 @@ + + + diff --git a/src/lib/components/questions/radio_group/radio_group_question_input.svelte b/src/lib/components/questions/radio_group/radio_group_question_input.svelte index 226fcb3..3d412c7 100644 --- a/src/lib/components/questions/radio_group/radio_group_question_input.svelte +++ b/src/lib/components/questions/radio_group/radio_group_question_input.svelte @@ -1,7 +1,7 @@
@@ -12,10 +12,10 @@ type="radio" required={data.required} name={data.name} - id={choice} + id={choice.value} checked={data.choiceIndex !== undefined && i === data.choiceIndex} /> - +
{/each} {#if data.allowCustomChoice} diff --git a/src/lib/components/questions/radio_group/radio_group_question_input_editor.svelte b/src/lib/components/questions/radio_group/radio_group_question_input_editor.svelte index e69de29..84915df 100644 --- a/src/lib/components/questions/radio_group/radio_group_question_input_editor.svelte +++ b/src/lib/components/questions/radio_group/radio_group_question_input_editor.svelte @@ -0,0 +1,47 @@ + + + +
+ allow custom choice + +
+
+ default choice index + +
+
+ defualt custom choice string + +
+
+ defualt value + +
+

Edit Choices

+ + +
+ +
+
+
diff --git a/src/lib/components/questions/select/select_add_item.svelte b/src/lib/components/questions/select/select_add_item.svelte new file mode 100644 index 0000000..f8472b7 --- /dev/null +++ b/src/lib/components/questions/select/select_add_item.svelte @@ -0,0 +1,20 @@ + + + diff --git a/src/lib/components/questions/select/select_question_input.svelte b/src/lib/components/questions/select/select_question_input.svelte index 33ebf02..802cef5 100644 --- a/src/lib/components/questions/select/select_question_input.svelte +++ b/src/lib/components/questions/select/select_question_input.svelte @@ -1,7 +1,7 @@
diff --git a/src/lib/components/questions/select/select_question_input_editor.svelte b/src/lib/components/questions/select/select_question_input_editor.svelte index ffdd4bb..9fa44fa 100644 --- a/src/lib/components/questions/select/select_question_input_editor.svelte +++ b/src/lib/components/questions/select/select_question_input_editor.svelte @@ -2,54 +2,44 @@ import type { SelectQuestion } from '$lib/form'; import { QuestionType } from '$lib/form'; import SelectQuestionInput from './select_question_input.svelte'; - - var newOption: string = ''; - - let data: SelectQuestion = { - type: QuestionType.SELECT, - options: [ - { value: '55', content: 'Apple' }, - { value: '66', content: 'Bananna' } - ], - name: '', - content: '' - }; - - // let other: TextQuestion = { - // type: QuestionType.TEXT, - // name: 'OOP', - // content: newOption - // }; - - function removeOption(option: unknown) { - var index = (data.options as unknown[]).indexOf(option); - if (index > -1) { - data.options.splice(index, 1); - data.options = data.options; - } - } - - function addOptions() { - if (/^.+$/.test(newOption)) { - if (data.options.includes({ value: newOption, content: newOption })) { - console.log('Key / value already exists for this value!'); - return; - } else { - // KV does not exist - data.options.push({ value: newOption, content: newOption }); - data.options = data.options; - newOption = ''; - } - } - } + import ListInput from '$lib/components/list_input/list_input.svelte'; + import TextQuestionInput from '../text/text_question_input.svelte'; + import SelectAddItem from './select_add_item.svelte'; + import DeleteItem from '$lib/components/form_editor/question_list_editor/delete_item.svelte'; + import BaseEditor from '../base/base_editor.svelte'; + import TextQuestionInputEditor from '../text/text_question_input_editor.svelte'; + import { AuditLogOptionsType } from 'discord-api-types/v10'; + import ChoiceEditor from '../base/choice_editor.svelte'; + + export var data = $$props as SelectQuestion; -
- -
+ + + +

Edit Choices

+ + +
+ +
+
+
diff --git a/src/lib/components/questions/text/text_question_input.svelte b/src/lib/components/questions/text/text_question_input.svelte index 82e2538..bbbf749 100644 --- a/src/lib/components/questions/text/text_question_input.svelte +++ b/src/lib/components/questions/text/text_question_input.svelte @@ -1,7 +1,7 @@
diff --git a/src/lib/components/questions/text/text_question_input_editor.svelte b/src/lib/components/questions/text/text_question_input_editor.svelte index e69de29..6b374a3 100644 --- a/src/lib/components/questions/text/text_question_input_editor.svelte +++ b/src/lib/components/questions/text/text_question_input_editor.svelte @@ -0,0 +1,51 @@ + + + + +
+ Min Length + +
+
+ Max Length + +
+
+ Default Value + +
+
+ Placeholder + +
+
+ Regex Pattern + +
+
+ Choices (COMMING SOON) +
+ +
+ +
+
+
diff --git a/src/lib/components/questions/textarea/textarea_question_input.svelte b/src/lib/components/questions/textarea/textarea_question_input.svelte index 898bd15..0028d8d 100644 --- a/src/lib/components/questions/textarea/textarea_question_input.svelte +++ b/src/lib/components/questions/textarea/textarea_question_input.svelte @@ -2,7 +2,7 @@ import type { TextareaQuestion } from '$lib/form'; import { adjustableTextareaHeight } from './adjustable_textarea_height'; - const data = $$props as TextareaQuestion; + export let data = $$props as TextareaQuestion;
diff --git a/src/lib/components/questions/textarea/textarea_question_input_editor.svelte b/src/lib/components/questions/textarea/textarea_question_input_editor.svelte index e69de29..48d5558 100644 --- a/src/lib/components/questions/textarea/textarea_question_input_editor.svelte +++ b/src/lib/components/questions/textarea/textarea_question_input_editor.svelte @@ -0,0 +1,31 @@ + + + +
+ Min Length + +
+
+ Max Length + +
+
+ Default Value + +
+
+ Placeholder + +
+ +
+ +
+
+
diff --git a/src/lib/components/questions/time/time_question_input.svelte b/src/lib/components/questions/time/time_question_input.svelte index 32c8602..d28ab28 100644 --- a/src/lib/components/questions/time/time_question_input.svelte +++ b/src/lib/components/questions/time/time_question_input.svelte @@ -1,7 +1,7 @@
@@ -10,7 +10,7 @@ name={data.name} type="time" required={data.required} - value={data.value} + bind:value={data.value} min={data.min} max={data.max} /> diff --git a/src/lib/components/questions/time/time_question_input_editor.svelte b/src/lib/components/questions/time/time_question_input_editor.svelte index e69de29..336deca 100644 --- a/src/lib/components/questions/time/time_question_input_editor.svelte +++ b/src/lib/components/questions/time/time_question_input_editor.svelte @@ -0,0 +1,28 @@ + + + + +
+ Min Time + +
+
+ Max Time + +
+
+ Default Time + +
+ +
+ +
+
+
diff --git a/src/lib/components/questions/timezone/timezone_question_input.svelte b/src/lib/components/questions/timezone/timezone_question_input.svelte index 41e7254..077e22d 100644 --- a/src/lib/components/questions/timezone/timezone_question_input.svelte +++ b/src/lib/components/questions/timezone/timezone_question_input.svelte @@ -2,7 +2,7 @@ import type { TimezoneQuestion } from '$lib/form'; import { TIMEZONES } from '$lib/timezones'; - const data = $$props as TimezoneQuestion; + export let data = $$props as TimezoneQuestion; let localTimezoneID = ''; if (Intl.DateTimeFormat) { @@ -10,9 +10,11 @@ } - - +
+ {data.content} + +
diff --git a/src/lib/components/questions/timezone/timezone_question_input_editor.svelte b/src/lib/components/questions/timezone/timezone_question_input_editor.svelte index e69de29..c8c02f8 100644 --- a/src/lib/components/questions/timezone/timezone_question_input_editor.svelte +++ b/src/lib/components/questions/timezone/timezone_question_input_editor.svelte @@ -0,0 +1,17 @@ + + + +
+ Defualt Timezone ID + +
+ + + +
diff --git a/src/lib/store/index.ts b/src/lib/db/index.ts similarity index 100% rename from src/lib/store/index.ts rename to src/lib/db/index.ts diff --git a/src/lib/store/kv/index.ts b/src/lib/db/kv/index.ts similarity index 100% rename from src/lib/store/kv/index.ts rename to src/lib/db/kv/index.ts diff --git a/src/lib/store/kv/kv.ts b/src/lib/db/kv/kv.ts similarity index 75% rename from src/lib/store/kv/kv.ts rename to src/lib/db/kv/kv.ts index c3927bc..341502c 100644 --- a/src/lib/store/kv/kv.ts +++ b/src/lib/db/kv/kv.ts @@ -1,5 +1,5 @@ import type { Kv, KvKey } from '@deno/kv'; -import type * as store from '$lib/store'; +import type * as db from '$lib/db'; export enum KvCollection { USERS_BY_DISCORD_USER_ID = 'users_by_discord_user_id', @@ -9,54 +9,54 @@ export enum KvCollection { SUBMISSIONS_BY_FORM_ID = 'submissions_by_form_id' } -export class KvStore implements store.Store { +export class KvStore implements db.Store { constructor(private readonly kv: Kv, private readonly kvNamespace: KvKey = []) {} - public async getForms(): Promise { + public async getForms(): Promise { const prefix = this.key(KvCollection.FORMS_BY_ID); - const forms: store.Form[] = []; - for await (const entry of this.kv.list({ prefix })) { + const forms: db.Form[] = []; + for await (const entry of this.kv.list({ prefix })) { forms.push(entry.value); } return forms; } - public async getFormByID(id: string): Promise { + public async getFormByID(id: string): Promise { const formKey = this.key(KvCollection.FORMS_BY_ID, id); - const formResult = await this.kv.get(formKey); + const formResult = await this.kv.get(formKey); return formResult.value; } public async getUserByDiscordUserID(id: string) { const userKey = this.key(KvCollection.USERS_BY_DISCORD_USER_ID, id); - const userResult = await this.kv.get(userKey); + const userResult = await this.kv.get(userKey); return userResult.value; } - public async getUserBySessionID(id: string): Promise { + public async getUserBySessionID(id: string): Promise { const userKey = this.key(KvCollection.USERS_BY_SESSION_ID, id); - const userResult = await this.kv.get(userKey); + const userResult = await this.kv.get(userKey); return userResult.value; } - public async getSubmissionByID(id: string): Promise { + public async getSubmissionByID(id: string): Promise { const submissionKey = this.key(KvCollection.SUBMISSIONS_BY_ID, id); - const submissionResult = await this.kv.get(submissionKey); + const submissionResult = await this.kv.get(submissionKey); return submissionResult.value; } - public async getSubmissionsByFormID(id: string): Promise { + public async getSubmissionsByFormID(id: string): Promise { const prefix = this.key(KvCollection.SUBMISSIONS_BY_FORM_ID, id); - const submissions: store.Submission[] = []; - for await (const entry of this.kv.list({ prefix })) { + const submissions: db.Submission[] = []; + for await (const entry of this.kv.list({ prefix })) { submissions.push(entry.value); } return submissions; } - public async createForm(r: store.CreateFormRequest): Promise { + public async createForm(r: db.CreateFormRequest): Promise { const formKey = this.key(KvCollection.FORMS_BY_ID, r.id); const result = await this.kv.set(formKey, r); if (!result.ok) { @@ -66,9 +66,9 @@ export class KvStore implements store.Store { return r; } - public async createUser(r: store.CreateUserRequest): Promise { - const id: store.ID = crypto.randomUUID(); - const user: store.User = { + public async createUser(r: db.CreateUserRequest): Promise { + const id: db.ID = crypto.randomUUID(); + const user: db.User = { id, discordUserID: r.discordUserID, discordUsername: r.discordUsername, @@ -94,12 +94,12 @@ export class KvStore implements store.Store { return user; } - public async createSession(r: store.CreateSessionRequest): Promise { + public async createSession(r: db.CreateSessionRequest): Promise { const usersByDiscordUserIDKey = this.key( KvCollection.USERS_BY_DISCORD_USER_ID, r.discordUserID ); - const userResult = await this.kv.get(usersByDiscordUserIDKey); + const userResult = await this.kv.get(usersByDiscordUserIDKey); if (!userResult.value) { throw new Error(`User not found for discordUserID: ${r.discordUserID}`); } @@ -124,7 +124,7 @@ export class KvStore implements store.Store { return updatedUser; } - public async createSubmission(r: store.CreateSubmissionRequest): Promise { + public async createSubmission(r: db.CreateSubmissionRequest): Promise { const submissionsByIDKey = this.key(KvCollection.SUBMISSIONS_BY_ID, r.id); const submissionsByFormIDKey = this.key(KvCollection.SUBMISSIONS_BY_FORM_ID, r.formID, r.id); // https://docs.deno.com/kv/manual/secondary_indexes#non-unique-indexes-one-to-many @@ -163,7 +163,7 @@ export class KvStore implements store.Store { public async deleteSubmissionByID(id: string): Promise { const submissionsByIDKey = this.key(KvCollection.SUBMISSIONS_BY_ID, id); - const submissionResult = await this.kv.get(submissionsByIDKey); + const submissionResult = await this.kv.get(submissionsByIDKey); if (!submissionResult.value) { throw new Error(`Submission not found for id: ${id}`); } diff --git a/src/lib/store/store.ts b/src/lib/db/store.ts similarity index 100% rename from src/lib/store/store.ts rename to src/lib/db/store.ts diff --git a/src/lib/form/form.ts b/src/lib/form/form.ts index 225c65a..91edc3d 100644 --- a/src/lib/form/form.ts +++ b/src/lib/form/form.ts @@ -212,7 +212,10 @@ export interface RadioGroupQuestion extends QuestionBase { * TODO: Update to choices: { value: string; content: string; }[]. * This will allow for custom choice values. Replace choiceIndex with value. */ - choices: string[]; + choices: { + value: string; + content: string; + }[]; /** * allowCustomChoice is whether or not the form field has a custom choice. @@ -419,7 +422,7 @@ export interface ColorQuestion extends QuestionBase { type: QuestionType.COLOR; /** - * value is the value value for the color input. + * value is the value for the color input. */ value?: string; } @@ -592,9 +595,9 @@ export interface TimezoneQuestion extends QuestionBase { type: QuestionType.TIMEZONE; /** - * default is the default value for the timezone question. + * value is the timezone. */ - default?: TimezoneQuestionValue['value']; + value?: TimezoneQuestionValue['value']; } /** diff --git a/src/lib/resources/store.ts b/src/lib/resources/store.ts index 1ece1a6..a35fea4 100644 --- a/src/lib/resources/store.ts +++ b/src/lib/resources/store.ts @@ -1,8 +1,8 @@ import { openKv } from '@deno/kv'; -import { KvStore } from '$lib/store/kv'; +import { KvStore } from '$lib/db/kv'; import { DENO_KV_ACCESS_TOKEN, DENO_KV_CONNECT_URL } from '$env/static/private'; -const kvPath = DENO_KV_CONNECT_URL || './.denokv'; +const kvPath = DENO_KV_CONNECT_URL || './db.kv'; const kv = await openKv(kvPath, { accessToken: DENO_KV_ACCESS_TOKEN }); export const s = new KvStore(kv); diff --git a/src/lib/stores/drafts/drafts.ts b/src/lib/stores/drafts/drafts.ts new file mode 100644 index 0000000..931a733 --- /dev/null +++ b/src/lib/stores/drafts/drafts.ts @@ -0,0 +1,6 @@ +import { writable } from 'svelte/store'; +import type { Form } from '$lib/form'; + +export const drafts = writable>(new Map()); + +// TODO: Dream about the solution diff --git a/src/routes/demo/demo_form.ts b/src/routes/demo/demo_form.ts index f9ad39e..572cab4 100644 --- a/src/routes/demo/demo_form.ts +++ b/src/routes/demo/demo_form.ts @@ -1,6 +1,7 @@ import type { Form } from '$lib/form'; import { QuestionType } from '$lib/form'; +// TODO: Add more questions to cover all question types. export const demoForm: Form = { id: 'demo_form_id', discordChannelID: '', @@ -29,7 +30,12 @@ export const demoForm: Form = { content: 'please pick one', required: false, allowCustomChoice: false, - choices: ['choice 1', 'choice 2', 'choice 3', 'choice 4'] + choices: [ + { value: 'choice1', content: 'choice 1' }, + { value: 'choice2', content: 'choice 2' }, + { value: 'choice3', content: 'choice 3' }, + { value: 'choice4', content: 'choice 4' } + ] }, { type: QuestionType.COLOR, diff --git a/src/routes/discord_oauth2/+server.ts b/src/routes/discord_oauth2/+server.ts index 159ff1b..076bcc3 100644 --- a/src/routes/discord_oauth2/+server.ts +++ b/src/routes/discord_oauth2/+server.ts @@ -1,5 +1,5 @@ import type { RequestHandler } from './$types'; -import type { CreateUserRequest } from '$lib/store'; +import type * as db from '$lib/db'; import { DISCORD_REDIRECT_URI, DISCORD_CLIENT_ID, @@ -81,7 +81,7 @@ export const GET: RequestHandler = async ({ url, locals }) => { return redirect; }; -function fromDiscordUser(sessionID: string, discordUser: DiscordUser): CreateUserRequest { +function fromDiscordUser(sessionID: string, discordUser: DiscordUser): db.CreateUserRequest { return { sessionID, discordUserID: discordUser.id, diff --git a/src/routes/forms/[form_id]/submissions.csv/+server.ts b/src/routes/forms/[form_id]/submissions.csv/+server.ts index 9f2d3d1..462f1ea 100644 --- a/src/routes/forms/[form_id]/submissions.csv/+server.ts +++ b/src/routes/forms/[form_id]/submissions.csv/+server.ts @@ -1,7 +1,7 @@ import type { RequestHandler } from './$types'; import * as exportToCSV from 'export-to-csv'; +import type * as db from '$lib/db'; import { s } from '$lib/resources/store'; -import type { Submission } from '$lib/store'; export const GET: RequestHandler = async ({ params }) => { const submissions = await s.getSubmissionsByFormID(params.form_id); @@ -14,7 +14,7 @@ export const GET: RequestHandler = async ({ params }) => { }; // TODO: Submissions to JSON. -function submissionsToCSV(submissions: Submission[]): string { +function submissionsToCSV(submissions: db.Submission[]): string { const config = exportToCSV.mkConfig({ useKeysAsHeaders: true }); const data = exportToCSV.generateCsv(config)( submissions.map((submission) => ({ diff --git a/src/routes/forms/demoformeditor/+page.svelte b/src/routes/forms/demoformeditor/+page.svelte new file mode 100644 index 0000000..0384a8a --- /dev/null +++ b/src/routes/forms/demoformeditor/+page.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/routes/forms/demoformeditor/demo_form_editor.ts b/src/routes/forms/demoformeditor/demo_form_editor.ts new file mode 100644 index 0000000..3bb4039 --- /dev/null +++ b/src/routes/forms/demoformeditor/demo_form_editor.ts @@ -0,0 +1,107 @@ +import type { Form } from '$lib/form'; +import { QuestionType } from '$lib/form'; + +// TODO: Add more questions to cover all question types. +export const demoForm: Form = { + id: 'demo_form_id', + discordChannelID: '', + startDate: '', + endDate: null, + questions: { + data: [ + { + type: QuestionType.BOOLEAN, + name: 'Age Check', + content: 'Are you over 18 years old?', + required: false, + value: true, + style: 'checkbox' + }, + { + type: QuestionType.TEXT, + name: 'FRQ', + content: 'How do you feel about this form?', + required: false, + value: 'Sample Text' + }, + { + type: QuestionType.RADIO_GROUP, + name: 'multiple choice', + content: 'please pick one', + required: false, + allowCustomChoice: false, + choices: [ + { content: 'choice 1', value: 'choice 1 value' }, + { content: 'choice 2', value: 'choice 2 value' }, + { content: 'choice 3', value: 'choice 3 value' } + ] + }, + { + type: QuestionType.COLOR, + name: 'Color Question', + content: 'Pick a color', + required: false, + value: '#000000' + }, + { + type: QuestionType.NUMBER, + name: 'Number Question', + content: 'Pick a number', + required: false, + min: 0, + max: 100, + placeholder: 'select a number' + }, + { + type: QuestionType.TEXTAREA, + name: 'Text Area Question', + content: 'text area?', + required: false, + minLength: 0, + maxLength: 1_000, + placeholder: 'write here', + value: '' + }, + { + type: QuestionType.SELECT, + name: 'Select Question', + content: 'Pick an option', + options: [{ value: 'text', content: 'test' }] + }, + { + type: QuestionType.DATE, + name: 'justDate', + content: 'Pick a date (jk you can only pick today)', + required: false, + value: '2024-04-10', + min: '2024-04-10', + max: '2024-04-10' + }, + { + type: QuestionType.DATETIME, + name: 'justDate', + content: 'Pick a date (jk you can only pick today)', + required: false, + value: '2024-04-10T11:11:11', + min: '2024-04-10T11:11:11', + max: '2024-04-10T11:11:11' + }, + { + type: QuestionType.TIME, + name: 'just time', + content: 'just time', + required: false, + value: '11:11:11', + min: '11:11:11', + max: '11:11:11' + }, + { + type: QuestionType.AVAILABILITY, + name: 'availability', + content: 'Availability Question?', + required: false, + value: [['2024-04-10T11:11:11', '2024-04-10T11:11:12']] + } + ] + } +};