From db6d36427db9e134c115a4fa27e7693c404355e0 Mon Sep 17 00:00:00 2001 From: Tobias Frischmann Date: Mon, 7 Sep 2026 16:45:31 +0200 Subject: [PATCH] basic organization create ui --- api/tests/organisation.rs | 10 +++ .../Settings/Organisations/CreateOrg.vue | 76 ++++++++++++++++ .../Settings/Organisations/JoinOrg.vue | 76 ++++++++++++++++ .../Settings/Organisations/Organisations.vue | 44 ++++++++++ app/components/Settings/SettingsSheet.vue | 2 + app/mutations/organisation.ts | 87 +++++++++++++++++++ app/queries/organisation.ts | 8 ++ app/utils/types.ts | 5 ++ 8 files changed, 308 insertions(+) create mode 100644 app/components/Settings/Organisations/CreateOrg.vue create mode 100644 app/components/Settings/Organisations/JoinOrg.vue create mode 100644 app/components/Settings/Organisations/Organisations.vue create mode 100644 app/mutations/organisation.ts create mode 100644 app/queries/organisation.ts diff --git a/api/tests/organisation.rs b/api/tests/organisation.rs index 8a825f3..ce51e82 100644 --- a/api/tests/organisation.rs +++ b/api/tests/organisation.rs @@ -179,3 +179,13 @@ async fn join_unknown_organisation() { response.assert_status_bad_request(); } + +#[tokio::test] +async fn join_already_joined_organisation() { + todo!() +} + +#[tokio::test] +async fn leave_already_leaved_organisation() { + todo!() +} diff --git a/app/components/Settings/Organisations/CreateOrg.vue b/app/components/Settings/Organisations/CreateOrg.vue new file mode 100644 index 0000000..116f286 --- /dev/null +++ b/app/components/Settings/Organisations/CreateOrg.vue @@ -0,0 +1,76 @@ + + + diff --git a/app/components/Settings/Organisations/JoinOrg.vue b/app/components/Settings/Organisations/JoinOrg.vue new file mode 100644 index 0000000..ea70824 --- /dev/null +++ b/app/components/Settings/Organisations/JoinOrg.vue @@ -0,0 +1,76 @@ + + + diff --git a/app/components/Settings/Organisations/Organisations.vue b/app/components/Settings/Organisations/Organisations.vue new file mode 100644 index 0000000..8207f73 --- /dev/null +++ b/app/components/Settings/Organisations/Organisations.vue @@ -0,0 +1,44 @@ + + + diff --git a/app/components/Settings/SettingsSheet.vue b/app/components/Settings/SettingsSheet.vue index cea4872..c0e05c1 100644 --- a/app/components/Settings/SettingsSheet.vue +++ b/app/components/Settings/SettingsSheet.vue @@ -4,6 +4,7 @@ import ApiKeys from "./ApiKeys.vue"; import Categories from "./Categories.vue"; import GoogleLogin from "./GoogleLogin.vue"; + import Organisations from "./Organisations/Organisations.vue"; import Tags from "./Tags.vue"; const isOpen = defineModel("isOpen", { required: true }); @@ -148,6 +149,7 @@ + diff --git a/app/mutations/organisation.ts b/app/mutations/organisation.ts new file mode 100644 index 0000000..077b72f --- /dev/null +++ b/app/mutations/organisation.ts @@ -0,0 +1,87 @@ +import { v4 } from "uuid"; + +export const useCreateOrganisation = defineMutation({ + async mutation(organisation: { name: string }, { uuid }: { uuid: UUID }) { + const { $api } = useNuxtApp(); + return await $api(`/api/organisation`, { + method: "POST", + body: { ...organisation, uuid }, + }); + }, + onMutate({ name }: { name: string }) { + const queryCache = useQueryCache(); + + const activeOrganisations = queryCache.getQueryData([ + "organisations", + ]); + if (!activeOrganisations) return; + + const organisation = { + uuid: v4(), + name, + }; + + activeOrganisations.push(organisation); + queryCache.setQueryData(["organisations"], [...activeOrganisations]); + + return { uuid: organisation.uuid }; + }, + onError(error) { + const { showError } = useToast(); + showError(error.message); + + const queryCache = useQueryCache(); + queryCache.invalidateQueries({ key: ["organisations"] }); + }, +}); + +export const useLeaveOrganisation = defineMutation({ + async mutation(uuid: string) { + const { $api } = useNuxtApp(); + return await $api(`/api/organisation/leave`, { + method: "POST", + body: { uuid: uuid }, + }); + }, + onMutate(uuid: string) { + const queryCache = useQueryCache(); + + const activeOrganisations = queryCache.getQueryData([ + "organisations", + ]); + if (!activeOrganisations) return; + + queryCache.setQueryData( + ["organisations"], + activeOrganisations.filter((organisation) => organisation.uuid !== uuid), + ); + }, + onError(error) { + const { showError } = useToast(); + showError(error.message); + + const queryCache = useQueryCache(); + queryCache.invalidateQueries({ key: ["organisations"] }); + }, +}); + +export const useJoinOrganisation = defineMutation({ + async mutation(uuid: string) { + const { $api } = useNuxtApp(); + return await $api(`/api/organisation/join`, { + method: "POST", + body: { uuid: uuid }, + }); + }, + onSettled: () => { + const queryCache = useQueryCache(); + queryCache.invalidateQueries({ key: ["organisations"] }); + }, + onError(error) { + const { showError } = useToast(); + showError(error.message); + + const queryCache = useQueryCache(); + queryCache.invalidateQueries({ key: ["organisations"] }); + }, +}); diff --git a/app/queries/organisation.ts b/app/queries/organisation.ts new file mode 100644 index 0000000..01d3e4d --- /dev/null +++ b/app/queries/organisation.ts @@ -0,0 +1,8 @@ +export const useOrganisationsQuery = defineQueryOptions(() => ({ + key: ["organisations"], + query: () => { + const { $api } = useNuxtApp(); + return $api("/api/organisation"); + }, + ssrCatchError: true, +})); diff --git a/app/utils/types.ts b/app/utils/types.ts index 55b37d9..368bb71 100644 --- a/app/utils/types.ts +++ b/app/utils/types.ts @@ -79,3 +79,8 @@ export type PushSubscriptionJSON = { p256dh: string; }; }; + +export type Organisation = { + uuid: UUID; + name: string; +}; -- 2.51.2