From 7ab4f7a6be82b07987dcbe7a9c8bd3949c70a164 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=90=BD?=
 <98581820+luo0602141017@users.noreply.github.com>
Date: Fri, 20 Dec 2024 22:18:32 +0800
Subject: [PATCH] feat(org): add create org (#125)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* release: alpha (#61)

* release: bump version (#63)

chore: publish new versions

Co-authored-by: fu050409 <46275354+fu050409@users.noreply.github.com>

* fix(lint): fix code spell check

* ci(release): remove `tailwindcss` building

* fix(profile): fix profile problem panel (#65)

* chore: fix aur release

* release: bump version (#66)

chore: publish new versions

Co-authored-by: fu050409 <46275354+fu050409@users.noreply.github.com>

* chore: fix code spell check

* feat: add `NProgress` bar (#67)

* feat: add n progress bar

* chore: bump version

* release: bump version (#68)

chore: publish new versions

Co-authored-by: fu050409 <46275354+fu050409@users.noreply.github.com>

* chore: fix aur ssh known hosts

* chore: fix version check

* release: alpha releases (#62)

* refactor(submit): enable code submission (#69)

* release: bump version (#70)

chore: publish new versions

Co-authored-by: fu050409 <46275354+fu050409@users.noreply.github.com>

* chore: try split aur release

* chore: fix aur action

* ci: add string in aur release

* ci(release): retry to aur release

* ci(release): fix covector ci

* release: bump version (#72)

chore: publish new versions

Co-authored-by: fu050409 <46275354+fu050409@users.noreply.github.com>

* revert(ci): revert aur release

* refactor(asset): full rewrite asset logic (#73)

* refactor(asset): full rewrite asset logic

* release: bump version (#74)

chore: publish new versions

Co-authored-by: fu050409 <46275354+fu050409@users.noreply.github.com>

* chore: fix aur release

* release: bump version (#75)

chore: publish new versions

Co-authored-by: fu050409 <46275354+fu050409@users.noreply.github.com>

* feat: optimize monaco editor error notification (#76)

* release: bump version (#77)

chore: publish new versions

Co-authored-by: fu050409 <46275354+fu050409@users.noreply.github.com>

* refactor(problem): sync changes with backend (#78)

* release: bump version (#79)

chore: publish new versions

Co-authored-by: fu050409 <46275354+fu050409@users.noreply.github.com>

* feat: optimize the code and add splash screen (#80)

* release: bump version (#81)

chore: publish new versions

Co-authored-by: fu050409 <46275354+fu050409@users.noreply.github.com>

* refactor: create problem page (#82)

* refactor: create problem page

* chore: fix code spell check

* feat: optimize problem page (#84)

* release: bump version (#83)

chore: publish new versions

Co-authored-by: fu050409 <46275354+fu050409@users.noreply.github.com>

* fix(problem): fix markdown preview (#85)

* release: bump version (#86)

chore: publish new versions

Co-authored-by: fu050409 <46275354+fu050409@users.noreply.github.com>

* feat(register): support for birthday (#87)

* feat(problem): support auto load submissions (#89)

* feat(problem): support auto load submissions

* chore: bump version

* release: bump version (#88)

chore: publish new versions

Co-authored-by: fu050409 <46275354+fu050409@users.noreply.github.com>

* feat(contest): support create contest (#90)

* release: bump version (#91)

chore: publish new versions

Co-authored-by: fu050409 <46275354+fu050409@users.noreply.github.com>

* fix: upload size limit (#92)

* fix(signup): fix optional fields (#93)

* release: bump version (#94)

chore: publish new versions

Co-authored-by: fu050409 <46275354+fu050409@users.noreply.github.com>

* feat(contest): support for contest page (#95)

* chore: prepare for beta release

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* chore: fix ci branches

* release: bump version (#96)

chore: publish new versions

Co-authored-by: fu050409 <46275354+fu050409@users.noreply.github.com>

* feat(contest): support acc (#97)

* feat(contest): support acc

* chore: bump version

* release: bump version (#98)

chore: publish new versions

Co-authored-by: fu050409 <46275354+fu050409@users.noreply.github.com>

* feat(org): inrt ui

* feat(org): inrt ui

* feat(org): inrt ui

* feat(org): inrt ui

* feat(org): inrt ui

* feat(org): inrt ui

* feat(org): inrt ui

* feat(org): inrt ui

* feat(org): edit org page

* feat(org): edit org page

* Update src/views/org/create.vue

* chore(org): bump version

* fix(scripts): fix release-aur

---------

Co-authored-by: 苏向夜 <46275354+fu050409@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: 苏向夜 <fu050409@163.com>
---
 .changes/org-create.md   |   5 ++
 pnpm-lock.yaml           |   5 ++
 src/scripts/api.ts       |  21 ++++++-
 src/views/org/create.vue | 132 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 162 insertions(+), 1 deletion(-)
 create mode 100644 .changes/org-create.md
 create mode 100644 src/views/org/create.vue

diff --git a/.changes/org-create.md b/.changes/org-create.md
new file mode 100644
index 0000000..9848b3a
--- /dev/null
+++ b/.changes/org-create.md
@@ -0,0 +1,5 @@
+---
+"algohub": patch:feat
+---
+
+Created a new org create page.
\ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d6a4cba..58e1a53 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1007,6 +1007,9 @@ packages:
   '@types/nprogress@0.2.3':
     resolution: {integrity: sha512-k7kRA033QNtC+gLc4VPlfnue58CM1iQLgn1IMAU8VPHGOj7oIHPp9UlhedEnD/Gl8evoCjwkZjlBORtZ3JByUA==}
 
+  '@types/nprogress@0.2.3':
+    resolution: {integrity: sha512-k7kRA033QNtC+gLc4VPlfnue58CM1iQLgn1IMAU8VPHGOj7oIHPp9UlhedEnD/Gl8evoCjwkZjlBORtZ3JByUA==}
+
   '@types/object-path@0.11.4':
     resolution: {integrity: sha512-4tgJ1Z3elF/tOMpA8JLVuR9spt9Ynsf7+JjqsQ2IqtiPJtcLoHoXcT6qU4E10cPFqyXX5HDm9QwIzZhBSkLxsw==}
 
@@ -4591,6 +4594,8 @@ snapshots:
 
   '@types/nprogress@0.2.3': {}
 
+  '@types/nprogress@0.2.3': {}
+
   '@types/object-path@0.11.4': {}
 
   '@types/path-browserify@1.0.3': {}
diff --git a/src/scripts/api.ts b/src/scripts/api.ts
index d42cff9..bac05e8 100644
--- a/src/scripts/api.ts
+++ b/src/scripts/api.ts
@@ -246,4 +246,23 @@ export const fetchRanks = async (id: string, auth: Credentials) => {
   } catch (error) {
     return handleAxiosError(AxiosError.from(error));
   }
-}
\ No newline at end of file
+}
+
+interface OrganizationData {
+  name: string;
+  display_name: string;
+  description: string;
+}
+
+export const createOrganization = async (auth: Credentials, form: OrganizationData) => {
+  try {
+    const response = await axios.post("/org/create", {
+      id: auth.id,
+      token: auth.token,
+      org: form,
+    });
+    return response.data as Response<Credentials>;
+  } catch (error) {
+    return handleAxiosError(AxiosError.from(error));
+  }
+};
diff --git a/src/views/org/create.vue b/src/views/org/create.vue
new file mode 100644
index 0000000..3687125
--- /dev/null
+++ b/src/views/org/create.vue
@@ -0,0 +1,132 @@
+<script setup lang="ts">
+import * as api from "@/scripts/api";
+import { useRouter } from 'vue-router';
+import { useAccountStore } from '@/scripts/store';
+import { ref } from 'vue';
+import { reactive } from 'vue';
+import { useToast } from 'primevue/usetoast';
+
+
+const path = [{ label: 'New Organization' }];
+
+const router = useRouter();
+const toast = useToast();
+
+const accountStore = useAccountStore();
+if (!accountStore.isLoggedIn) {
+    toast.add({ severity: 'error', summary: 'Error', detail: 'Please login first', life: 3000 });
+    router.push('/login');
+}
+
+
+const initialValues = reactive({
+    org_name: "",
+    contact_email: "",
+    terms: false,
+});
+
+interface OrgCreateForm<T> {
+    org_name?: T;
+    contact_email?: T;
+    terms?: T;
+}
+
+const resolver = ({ values }: { values: OrgCreateForm<string> }) => {
+    const errors: OrgCreateForm<{ message: string }[]> = {};
+
+    if (!values.org_name) {
+        errors.org_name = [{ message: 'Organization Name is required.' }];
+    }
+
+    if (!values.contact_email) {
+        errors.contact_email = [{ message: 'Your Contact Email is required.' }];
+    }
+
+    if (!values.terms) {
+        errors.terms = [{ message: "You must agree to the terms and conditions." }]
+    }
+
+    return {
+        errors
+    };
+};
+
+const name = ref('');
+const email = ref('');
+const description = ref('');
+const display_name = ref('');
+
+const inProgress = ref(false);
+const onCreateOrg = async () => {
+    inProgress.value = true;
+    const res = await api.createOrganization(
+        accountStore.auth!,
+        {
+            name: name.value,
+            description: description.value,
+            display_name: display_name.value,
+        })
+    if (!res.success) {
+        toast.add({ severity: 'error', summary: 'Error', detail: res.message, life: 3000 });
+    };
+    inProgress.value = false;
+//    router.push("/org/create" + res.data!.id);
+// TODO: redirect to organization home page
+}
+</script>
+
+
+
+<template>
+    <div class="flex-1 flex flex-col">
+        <UniversalToolBar :path></UniversalToolBar>
+        <div class="max-w-full w-[768px] md:max-w-[768px] mx-auto">
+            <Panel class="mt-10 w-full h-full">
+                <div class="flex flex-col gap-8 w-full">
+                    <div class="mt-10 text-center">
+                        <span class="text-gray-500 mb-4">Tell us about your organization</span>
+                        <h1 class="text-3xl font-bold">Set up your organization</h1>
+                    </div>
+                    <div class="flex flex-col">
+                        <Form v-slot="$form" :initialValues :resolver class="flex flex-col gap-4 w-full ">
+                            <div class="card flex flex-col justify-center">
+                                <div class="flex flex-col">
+                                    <label for="name" style="font-size: 20px;">Organization Name *</label>
+                                    <InputText v-model="name" name="name"></InputText>
+                                </div>
+                                <Message v-if="$form.org_name?.invalid" severity="error" size="small" variant="simple">
+                                    {{
+                                        $form.org_name.error.message }}</Message>
+                                <div>
+                                    <span class="text-gray-500 mb-4" style="font-size:13px">This will be the name of
+                                        your
+                                        organization on AlgoHub.</span>
+                                </div>
+                                <div class="mt-6 flex flex-col">
+                                    <label for="email" style="font-size: 20px;">Contact Email *</label>
+                                    <InputText v-model="email" email="email"></InputText>
+                                </div>
+                                <Message v-if="$form.contact_email?.invalid" severity="error" size="small"
+                                    variant="simple">
+                                    {{
+                                        $form.contact_email.error.message }}</Message>
+                            </div>
+                            <div class="flex flex-col gap-1 w-full">
+                                <div class="flex items-center gap-2">
+                                    <Checkbox inputId="terms" name="terms" binary />
+                                    <label for="terms" class="text-sm">I have read and agree to the <a href="#"
+                                            class="underline">Affero
+                                            General Public License v3</a>.</label>
+                                </div>
+                                <Message v-if="$form.terms?.invalid" severity="error" size="small" variant="simple">{{
+                                    $form.terms.error.message }}</Message>
+                            </div>
+                            <Button @click="onCreateOrg" :loading="inProgress" label="Next"></Button>
+                        </Form>
+                    </div>
+                </div>
+            </Panel>
+        </div>
+        <UniversalFooter></UniversalFooter>
+    </div>
+</template>