diff --git a/frontend/package.json b/frontend/package.json index c2fff9d..fd766a9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -17,6 +17,7 @@ "@sveltejs/kit": "^1.5.0", "@tailwindcss/forms": "^0.5.3", "@tailwindcss/typography": "^0.5.9", + "@types/luxon": "^3.2.0", "@types/marked": "^4.0.8", "@types/sanitize-html": "^2.8.1", "@typescript-eslint/eslint-plugin": "^5.45.0", @@ -42,6 +43,7 @@ "base64-arraybuffer": "^1.0.2", "bootstrap": "5.3.0-alpha1", "bootstrap-icons": "^1.10.3", + "luxon": "^3.3.0", "marked": "^4.2.12", "sanitize-html": "^2.10.0", "sveltestrap": "^5.10.0" diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 4d41fc5..9b5901d 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -8,6 +8,7 @@ specifiers: '@sveltejs/kit': ^1.5.0 '@tailwindcss/forms': ^0.5.3 '@tailwindcss/typography': ^0.5.9 + '@types/luxon': ^3.2.0 '@types/marked': ^4.0.8 '@types/sanitize-html': ^2.8.1 '@typescript-eslint/eslint-plugin': ^5.45.0 @@ -19,6 +20,7 @@ specifiers: eslint: ^8.28.0 eslint-config-prettier: ^8.5.0 eslint-plugin-svelte3: ^4.0.0 + luxon: ^3.3.0 marked: ^4.2.12 postcss: ^8.4.21 prettier: ^2.8.0 @@ -38,6 +40,7 @@ dependencies: base64-arraybuffer: 1.0.2 bootstrap: 5.3.0-alpha1_@popperjs+core@2.11.6 bootstrap-icons: 1.10.3 + luxon: 3.3.0 marked: 4.2.12 sanitize-html: 2.10.0 sveltestrap: 5.10.0_svelte@3.55.1 @@ -48,6 +51,7 @@ devDependencies: '@sveltejs/kit': 1.11.0_svelte@3.55.1+vite@4.1.4 '@tailwindcss/forms': 0.5.3_tailwindcss@3.2.7 '@tailwindcss/typography': 0.5.9_tailwindcss@3.2.7 + '@types/luxon': 3.2.0 '@types/marked': 4.0.8 '@types/sanitize-html': 2.8.1 '@typescript-eslint/eslint-plugin': 5.54.1_mlk7dnz565t663n4razh6a6v6i @@ -555,6 +559,10 @@ packages: resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} dev: true + /@types/luxon/3.2.0: + resolution: {integrity: sha512-lGmaGFoaXHuOLXFvuju2bfvZRqxAqkHPx9Y9IQdQABrinJJshJwfNCKV+u7rR3kJbiqfTF/NhOkcxxAFrObyaA==} + dev: true + /@types/marked/4.0.8: resolution: {integrity: sha512-HVNzMT5QlWCOdeuBsgXP8EZzKUf0+AXzN+sLmjvaB3ZlLqO+e4u0uXrdw9ub69wBKFs+c6/pA4r9sy6cCDvImw==} dev: true @@ -1605,6 +1613,11 @@ packages: resolution: {integrity: sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==} dev: false + /luxon/3.3.0: + resolution: {integrity: sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==} + engines: {node: '>=12'} + dev: false + /magic-string/0.27.0: resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} engines: {node: '>=12'} diff --git a/frontend/src/routes/settings/export/+page.svelte b/frontend/src/routes/settings/export/+page.svelte new file mode 100644 index 0000000..b167e92 --- /dev/null +++ b/frontend/src/routes/settings/export/+page.svelte @@ -0,0 +1,83 @@ + + +
+

+ Data export + +

+ + {#if error} + + {/if} + + {#if data.exportData} +
+ {#if durationSinceCreated.days < minTimeBetween.days} + + You can only export your data once a day. You can next export your data at {createdAt.plus(minTimeBetween).toLocaleString(DateTime.DATETIME_MED)}. + + {/if} +

+ You last exported your data at {createdAt.toLocaleString(DateTime.DATETIME_MED)}. +
+ This file will be available until {createdAt + .plus(availableFor) + .toLocal() + .toLocaleString(DateTime.DATETIME_MED)} +
+ Download your export file below: +

+

+ +

+
+ {:else} + + You haven't exported your data in the past week. To create an export file, click the button + above. + + {/if} +
diff --git a/frontend/src/routes/settings/export/+page.ts b/frontend/src/routes/settings/export/+page.ts new file mode 100644 index 0000000..437a087 --- /dev/null +++ b/frontend/src/routes/settings/export/+page.ts @@ -0,0 +1,19 @@ +import { ErrorCode, type APIError } from "$lib/api/entities"; +import { apiFetchClient } from "$lib/api/fetch"; +import { error } from "@sveltejs/kit"; + +export const load = async () => { + try { + const data = await apiFetchClient("/auth/export"); + return { exportData: data }; + } catch (e) { + if ((e as APIError).code === ErrorCode.NotFound) return { exportData: null }; + + throw error((e as APIError).code, (e as APIError).message); + } +}; + +interface ExportResponse { + path: string; + created_at: Date; +} diff --git a/frontend/src/routes/settings/tokens/+page.svelte b/frontend/src/routes/settings/tokens/+page.svelte new file mode 100644 index 0000000..c337520 --- /dev/null +++ b/frontend/src/routes/settings/tokens/+page.svelte @@ -0,0 +1,3 @@ +

API tokens

+ +

This page is a work in progress, sorry!