diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5d12634 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +# editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7056274..55e0a29 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,6 +10,7 @@ on: permissions: contents: read # for checkout + packages: read jobs: commitlint: @@ -23,6 +24,10 @@ jobs: uses: actions/setup-node@v4 with: node-version: v22.12.0 + - name: Create .npmrc + run: | + echo "@OrdinarySMP:registry=https://npm.pkg.github.com" > .npmrc + echo "//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}" >> .npmrc - name: Install commitlint run: yarn add commitlint@latest conventional-changelog-conventionalcommits @commitlint/config-conventional - name: Validate current commit (last commit) with commitlint @@ -41,8 +46,14 @@ jobs: uses: actions/setup-node@v4 with: node-version: v22.12.0 + - name: Create .npmrc + run: | + echo "@OrdinarySMP:registry=https://npm.pkg.github.com" > .npmrc + echo "//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}" >> .npmrc - name: Install dependencies run: yarn install --frozen-lockfile + - name: Run typecheck + run: yarn typecheck - name: Run linter run: yarn eslint-ci - name: Run prettier diff --git a/.gitignore b/.gitignore index 4a7f73a..3f5a3bb 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ logs .env .env.* !.env.example +.npmrc diff --git a/app/app.config.ts b/app/app.config.ts new file mode 100644 index 0000000..30ee66f --- /dev/null +++ b/app/app.config.ts @@ -0,0 +1,7 @@ +export default defineAppConfig({ + ui: { + colors: { + brand: "brand", + }, + }, +}); diff --git a/app/app.vue b/app/app.vue new file mode 100644 index 0000000..5acf3c1 --- /dev/null +++ b/app/app.vue @@ -0,0 +1,7 @@ + diff --git a/app/assets/css/main.css b/app/assets/css/main.css new file mode 100644 index 0000000..043c438 --- /dev/null +++ b/app/assets/css/main.css @@ -0,0 +1,30 @@ +@import "tailwindcss"; +@import "@nuxt/ui"; + +@theme { + --color-brand-50: #fff3ea; + --color-brand-100: #ffe1cc; + --color-brand-200: #ffc599; + --color-brand-300: #ffa866; + --color-brand-400: #f88b47; + --color-brand-500: #f0833a; + --color-brand-600: #d66d2a; + --color-brand-700: #b8581f; + --color-brand-800: #964518; + --color-brand-900: #6e3212; + --color-brand-950: #3a1808; +} + +:root { + --color-primary-50: var(--color-brand-50); + --color-primary-100: var(--color-brand-100); + --color-primary-200: var(--color-brand-200); + --color-primary-300: var(--color-brand-300); + --color-primary-400: var(--color-brand-400); + --color-primary-500: var(--color-brand-500); + --color-primary-600: var(--color-brand-600); + --color-primary-700: var(--color-brand-700); + --color-primary-800: var(--color-brand-800); + --color-primary-900: var(--color-brand-900); + --color-primary-950: var(--color-brand-950); +} diff --git a/assets/logo-small.png b/app/assets/logo-small.png similarity index 100% rename from assets/logo-small.png rename to app/assets/logo-small.png diff --git a/assets/logo.png b/app/assets/logo.png similarity index 100% rename from assets/logo.png rename to app/assets/logo.png diff --git a/components/Layout/Logo.vue b/app/components/AppLogo.vue similarity index 100% rename from components/Layout/Logo.vue rename to app/components/AppLogo.vue diff --git a/app/components/TextChannelSelector.vue b/app/components/TextChannelSelector.vue new file mode 100644 index 0000000..b635d4e --- /dev/null +++ b/app/components/TextChannelSelector.vue @@ -0,0 +1,68 @@ + + + diff --git a/app/components/application/action-cell.vue b/app/components/application/action-cell.vue new file mode 100644 index 0000000..53b6374 --- /dev/null +++ b/app/components/application/action-cell.vue @@ -0,0 +1,124 @@ + + + diff --git a/app/components/application/button-fields.vue b/app/components/application/button-fields.vue new file mode 100644 index 0000000..8129912 --- /dev/null +++ b/app/components/application/button-fields.vue @@ -0,0 +1,54 @@ + + + diff --git a/app/components/application/fields.vue b/app/components/application/fields.vue new file mode 100644 index 0000000..98f9b4e --- /dev/null +++ b/app/components/application/fields.vue @@ -0,0 +1,13 @@ + + + diff --git a/app/components/application/form.vue b/app/components/application/form.vue new file mode 100644 index 0000000..d0566a9 --- /dev/null +++ b/app/components/application/form.vue @@ -0,0 +1,112 @@ + + + diff --git a/app/components/application/general-fields.vue b/app/components/application/general-fields.vue new file mode 100644 index 0000000..7d1327c --- /dev/null +++ b/app/components/application/general-fields.vue @@ -0,0 +1,44 @@ + + + diff --git a/app/components/application/question/action-cell.vue b/app/components/application/question/action-cell.vue new file mode 100644 index 0000000..1a32ed0 --- /dev/null +++ b/app/components/application/question/action-cell.vue @@ -0,0 +1,76 @@ + + + diff --git a/app/components/application/question/fields.vue b/app/components/application/question/fields.vue new file mode 100644 index 0000000..e3ee6f4 --- /dev/null +++ b/app/components/application/question/fields.vue @@ -0,0 +1,16 @@ + + + diff --git a/app/components/application/question/form.vue b/app/components/application/question/form.vue new file mode 100644 index 0000000..cbe395a --- /dev/null +++ b/app/components/application/question/form.vue @@ -0,0 +1,59 @@ + + + diff --git a/app/components/application/response/action-cell.vue b/app/components/application/response/action-cell.vue new file mode 100644 index 0000000..91c5632 --- /dev/null +++ b/app/components/application/response/action-cell.vue @@ -0,0 +1,76 @@ + + + diff --git a/app/components/application/response/fields.vue b/app/components/application/response/fields.vue new file mode 100644 index 0000000..a910bfa --- /dev/null +++ b/app/components/application/response/fields.vue @@ -0,0 +1,34 @@ + + + diff --git a/app/components/application/response/form.vue b/app/components/application/response/form.vue new file mode 100644 index 0000000..dc4fb8d --- /dev/null +++ b/app/components/application/response/form.vue @@ -0,0 +1,62 @@ + + + diff --git a/app/components/application/roles-fields.vue b/app/components/application/roles-fields.vue new file mode 100644 index 0000000..959cd3c --- /dev/null +++ b/app/components/application/roles-fields.vue @@ -0,0 +1,96 @@ + + + diff --git a/app/components/application/submission/action-cell.vue b/app/components/application/submission/action-cell.vue new file mode 100644 index 0000000..fecf58c --- /dev/null +++ b/app/components/application/submission/action-cell.vue @@ -0,0 +1,76 @@ + + + diff --git a/app/components/card/application.vue b/app/components/card/application.vue new file mode 100644 index 0000000..deb89f9 --- /dev/null +++ b/app/components/card/application.vue @@ -0,0 +1,64 @@ + + + diff --git a/app/components/card/bot-token.vue b/app/components/card/bot-token.vue new file mode 100644 index 0000000..a73bbbd --- /dev/null +++ b/app/components/card/bot-token.vue @@ -0,0 +1,78 @@ + + + diff --git a/app/components/card/ticket.vue b/app/components/card/ticket.vue new file mode 100644 index 0000000..169f51c --- /dev/null +++ b/app/components/card/ticket.vue @@ -0,0 +1,56 @@ + + + diff --git a/app/components/faq/action-cell.vue b/app/components/faq/action-cell.vue new file mode 100644 index 0000000..699a48c --- /dev/null +++ b/app/components/faq/action-cell.vue @@ -0,0 +1,71 @@ + + + diff --git a/app/components/faq/fields.vue b/app/components/faq/fields.vue new file mode 100644 index 0000000..98f9b4e --- /dev/null +++ b/app/components/faq/fields.vue @@ -0,0 +1,13 @@ + + + diff --git a/app/components/faq/form.vue b/app/components/faq/form.vue new file mode 100644 index 0000000..bdf65ae --- /dev/null +++ b/app/components/faq/form.vue @@ -0,0 +1,55 @@ + + + diff --git a/app/components/permission/fields.vue b/app/components/permission/fields.vue new file mode 100644 index 0000000..aef5d2e --- /dev/null +++ b/app/components/permission/fields.vue @@ -0,0 +1,73 @@ + + + diff --git a/app/components/permission/form.vue b/app/components/permission/form.vue new file mode 100644 index 0000000..4c33dfe --- /dev/null +++ b/app/components/permission/form.vue @@ -0,0 +1,122 @@ + + + diff --git a/app/components/profile/fields.vue b/app/components/profile/fields.vue new file mode 100644 index 0000000..cb0b4cd --- /dev/null +++ b/app/components/profile/fields.vue @@ -0,0 +1,55 @@ + + + diff --git a/app/components/profile/form.vue b/app/components/profile/form.vue new file mode 100644 index 0000000..23dd41a --- /dev/null +++ b/app/components/profile/form.vue @@ -0,0 +1,67 @@ + + + diff --git a/app/components/reaction-role/action-cell.vue b/app/components/reaction-role/action-cell.vue new file mode 100644 index 0000000..776b44f --- /dev/null +++ b/app/components/reaction-role/action-cell.vue @@ -0,0 +1,76 @@ + + + diff --git a/app/components/reaction-role/fields.vue b/app/components/reaction-role/fields.vue new file mode 100644 index 0000000..4108507 --- /dev/null +++ b/app/components/reaction-role/fields.vue @@ -0,0 +1,52 @@ + + + diff --git a/app/components/reaction-role/form.vue b/app/components/reaction-role/form.vue new file mode 100644 index 0000000..65ff5b8 --- /dev/null +++ b/app/components/reaction-role/form.vue @@ -0,0 +1,58 @@ + + + diff --git a/app/components/rule/action-cell.vue b/app/components/rule/action-cell.vue new file mode 100644 index 0000000..6bdd527 --- /dev/null +++ b/app/components/rule/action-cell.vue @@ -0,0 +1,71 @@ + + + diff --git a/app/components/rule/fields.vue b/app/components/rule/fields.vue new file mode 100644 index 0000000..03d7c21 --- /dev/null +++ b/app/components/rule/fields.vue @@ -0,0 +1,16 @@ + + + diff --git a/app/components/rule/form.vue b/app/components/rule/form.vue new file mode 100644 index 0000000..319fe09 --- /dev/null +++ b/app/components/rule/form.vue @@ -0,0 +1,56 @@ + + + diff --git a/app/components/server-content/action-cell.vue b/app/components/server-content/action-cell.vue new file mode 100644 index 0000000..b0b04bd --- /dev/null +++ b/app/components/server-content/action-cell.vue @@ -0,0 +1,76 @@ + + + diff --git a/app/components/server-content/fields.vue b/app/components/server-content/fields.vue new file mode 100644 index 0000000..555ef46 --- /dev/null +++ b/app/components/server-content/fields.vue @@ -0,0 +1,22 @@ + + + diff --git a/app/components/server-content/form.vue b/app/components/server-content/form.vue new file mode 100644 index 0000000..7515aec --- /dev/null +++ b/app/components/server-content/form.vue @@ -0,0 +1,60 @@ + + + diff --git a/app/components/server-content/message/fields.vue b/app/components/server-content/message/fields.vue new file mode 100644 index 0000000..bbd3810 --- /dev/null +++ b/app/components/server-content/message/fields.vue @@ -0,0 +1,29 @@ + + + diff --git a/app/components/server-content/message/form.vue b/app/components/server-content/message/form.vue new file mode 100644 index 0000000..fdaaf57 --- /dev/null +++ b/app/components/server-content/message/form.vue @@ -0,0 +1,64 @@ + + + diff --git a/app/components/table/boolean-cell.vue b/app/components/table/boolean-cell.vue new file mode 100644 index 0000000..b62f831 --- /dev/null +++ b/app/components/table/boolean-cell.vue @@ -0,0 +1,14 @@ + + + diff --git a/app/components/ticket/action-cell.vue b/app/components/ticket/action-cell.vue new file mode 100644 index 0000000..751cbff --- /dev/null +++ b/app/components/ticket/action-cell.vue @@ -0,0 +1,55 @@ + + + diff --git a/app/components/ticket/button/action-cell.vue b/app/components/ticket/button/action-cell.vue new file mode 100644 index 0000000..4193493 --- /dev/null +++ b/app/components/ticket/button/action-cell.vue @@ -0,0 +1,76 @@ + + + diff --git a/app/components/ticket/button/fields.vue b/app/components/ticket/button/fields.vue new file mode 100644 index 0000000..4e9702b --- /dev/null +++ b/app/components/ticket/button/fields.vue @@ -0,0 +1,109 @@ + + + diff --git a/app/components/ticket/button/form.vue b/app/components/ticket/button/form.vue new file mode 100644 index 0000000..7104870 --- /dev/null +++ b/app/components/ticket/button/form.vue @@ -0,0 +1,66 @@ + + + diff --git a/app/components/ticket/config/fields.vue b/app/components/ticket/config/fields.vue new file mode 100644 index 0000000..67a9898 --- /dev/null +++ b/app/components/ticket/config/fields.vue @@ -0,0 +1,29 @@ + + + diff --git a/app/components/ticket/config/form.vue b/app/components/ticket/config/form.vue new file mode 100644 index 0000000..1f53781 --- /dev/null +++ b/app/components/ticket/config/form.vue @@ -0,0 +1,63 @@ + + + diff --git a/app/components/ticket/panel/action-cell.vue b/app/components/ticket/panel/action-cell.vue new file mode 100644 index 0000000..dd85465 --- /dev/null +++ b/app/components/ticket/panel/action-cell.vue @@ -0,0 +1,98 @@ + + + diff --git a/app/components/ticket/panel/fields.vue b/app/components/ticket/panel/fields.vue new file mode 100644 index 0000000..48fce2b --- /dev/null +++ b/app/components/ticket/panel/fields.vue @@ -0,0 +1,39 @@ + + + diff --git a/app/components/ticket/panel/form.vue b/app/components/ticket/panel/form.vue new file mode 100644 index 0000000..bda981b --- /dev/null +++ b/app/components/ticket/panel/form.vue @@ -0,0 +1,61 @@ + + + diff --git a/app/components/ticket/team/action-cell.vue b/app/components/ticket/team/action-cell.vue new file mode 100644 index 0000000..5dd680b --- /dev/null +++ b/app/components/ticket/team/action-cell.vue @@ -0,0 +1,76 @@ + + + diff --git a/app/components/ticket/team/fields.vue b/app/components/ticket/team/fields.vue new file mode 100644 index 0000000..929fd7d --- /dev/null +++ b/app/components/ticket/team/fields.vue @@ -0,0 +1,21 @@ + + + diff --git a/app/components/ticket/team/form.vue b/app/components/ticket/team/form.vue new file mode 100644 index 0000000..1e43288 --- /dev/null +++ b/app/components/ticket/team/form.vue @@ -0,0 +1,59 @@ + + + diff --git a/components/Ticket/Transcript/Attachement.vue b/app/components/ticket/transcript/attachement.vue similarity index 100% rename from components/Ticket/Transcript/Attachement.vue rename to app/components/ticket/transcript/attachement.vue diff --git a/components/Ticket/Transcript/Embed.vue b/app/components/ticket/transcript/embed.vue similarity index 100% rename from components/Ticket/Transcript/Embed.vue rename to app/components/ticket/transcript/embed.vue diff --git a/app/composables/api-client.ts b/app/composables/api-client.ts new file mode 100644 index 0000000..15e7c54 --- /dev/null +++ b/app/composables/api-client.ts @@ -0,0 +1,7 @@ +export const useApiClient = () => { + const client = useSanctumClient(); + const config = useRuntimeConfig(); + return client.create({ + baseURL: `${config.public.sanctum.baseUrl}/api/v1`, + }); +}; diff --git a/app/composables/api-form.ts b/app/composables/api-form.ts new file mode 100644 index 0000000..cbffcce --- /dev/null +++ b/app/composables/api-form.ts @@ -0,0 +1,26 @@ +import type { FormSubmitEvent, Form } from "#ui/types"; +import type { LaravelValidationResponse } from "@/types/form"; + +export const useApiForm = ( + form: Ref | undefined>, + callback: (event: FormSubmitEvent) => void | Promise, +) => { + const submitting = ref(false); + + async function onSubmit(event: FormSubmitEvent) { + submitting.value = true; + try { + await callback(event); + } catch (err) { + const response = err as LaravelValidationResponse; + if (response.statusCode === 422) { + form.value!.setErrors( + laravelValidationErrorToNuxtUiForm(response.data), + ); + } + } finally { + submitting.value = false; + } + } + return { submitting, onSubmit }; +}; diff --git a/app/composables/api.ts b/app/composables/api.ts new file mode 100644 index 0000000..52921ab --- /dev/null +++ b/app/composables/api.ts @@ -0,0 +1,13 @@ +import type { UseFetchOptions } from "nuxt/app"; + +export const useApi = async ( + url: string | (() => string), + options?: UseFetchOptions, +) => { + const client = useApiClient(); + + return await useFetch(url, { + ...options, + $fetch: client as typeof $fetch, + }); +}; diff --git a/app/composables/current-user.ts b/app/composables/current-user.ts new file mode 100644 index 0000000..ac8c352 --- /dev/null +++ b/app/composables/current-user.ts @@ -0,0 +1,5 @@ +import type { UserData } from "@OrdinarySMP/api-types"; + +export const useCurrentUser = () => { + return useSanctumUser(); +}; diff --git a/app/composables/toast.ts b/app/composables/toast.ts new file mode 100644 index 0000000..a6bae8b --- /dev/null +++ b/app/composables/toast.ts @@ -0,0 +1,21 @@ +export const useSimpleToast = () => { + const toast = useToast(); + + const success = (message: string) => { + toast.add({ + title: message, + icon: "mdi:check-circle-outline", + color: "success" as const, + }); + }; + + const error = (message: string) => { + toast.add({ + title: message, + icon: "mdi:circle-off-outline", + color: "error" as const, + }); + }; + + return { success, error }; +}; diff --git a/app/layouts/default.vue b/app/layouts/default.vue new file mode 100644 index 0000000..33e5e08 --- /dev/null +++ b/app/layouts/default.vue @@ -0,0 +1,177 @@ + + + diff --git a/layouts/guest.vue b/app/layouts/guest.vue similarity index 100% rename from layouts/guest.vue rename to app/layouts/guest.vue diff --git a/app/middleware/permission.global.ts b/app/middleware/permission.global.ts new file mode 100644 index 0000000..aad9aef --- /dev/null +++ b/app/middleware/permission.global.ts @@ -0,0 +1,15 @@ +type PermissionMeta = { + permission: string; + fallback?: string; +}; + +export default defineNuxtRouteMiddleware(async (to) => { + const permission = to.meta.permission as PermissionMeta | undefined; + if (!permission) { + return; + } + + if (!hasPermissionTo(permission.permission)) { + return navigateTo(permission.fallback ?? "/"); + } +}); diff --git a/app/pages/application/[applicationId]/question/create.vue b/app/pages/application/[applicationId]/question/create.vue new file mode 100644 index 0000000..92509fb --- /dev/null +++ b/app/pages/application/[applicationId]/question/create.vue @@ -0,0 +1,61 @@ + + + diff --git a/app/pages/application/[applicationId]/question/edit/[id].vue b/app/pages/application/[applicationId]/question/edit/[id].vue new file mode 100644 index 0000000..8fa70b7 --- /dev/null +++ b/app/pages/application/[applicationId]/question/edit/[id].vue @@ -0,0 +1,52 @@ + + + diff --git a/app/pages/application/[applicationId]/question/index.vue b/app/pages/application/[applicationId]/question/index.vue new file mode 100644 index 0000000..e21ec10 --- /dev/null +++ b/app/pages/application/[applicationId]/question/index.vue @@ -0,0 +1,107 @@ + + + diff --git a/app/pages/application/[applicationId]/response/create.vue b/app/pages/application/[applicationId]/response/create.vue new file mode 100644 index 0000000..4afb106 --- /dev/null +++ b/app/pages/application/[applicationId]/response/create.vue @@ -0,0 +1,61 @@ + + + diff --git a/app/pages/application/[applicationId]/response/edit/[id].vue b/app/pages/application/[applicationId]/response/edit/[id].vue new file mode 100644 index 0000000..0281acf --- /dev/null +++ b/app/pages/application/[applicationId]/response/edit/[id].vue @@ -0,0 +1,52 @@ + + + diff --git a/app/pages/application/[applicationId]/response/index.vue b/app/pages/application/[applicationId]/response/index.vue new file mode 100644 index 0000000..e393bca --- /dev/null +++ b/app/pages/application/[applicationId]/response/index.vue @@ -0,0 +1,107 @@ + + + diff --git a/app/pages/application/create.vue b/app/pages/application/create.vue new file mode 100644 index 0000000..73ba7b3 --- /dev/null +++ b/app/pages/application/create.vue @@ -0,0 +1,45 @@ + + + diff --git a/app/pages/application/edit/[id].vue b/app/pages/application/edit/[id].vue new file mode 100644 index 0000000..b6413fb --- /dev/null +++ b/app/pages/application/edit/[id].vue @@ -0,0 +1,52 @@ + + + diff --git a/app/pages/application/index.vue b/app/pages/application/index.vue new file mode 100644 index 0000000..0100e6d --- /dev/null +++ b/app/pages/application/index.vue @@ -0,0 +1,101 @@ + + + diff --git a/app/pages/application/submission/index.vue b/app/pages/application/submission/index.vue new file mode 100644 index 0000000..78b34d6 --- /dev/null +++ b/app/pages/application/submission/index.vue @@ -0,0 +1,180 @@ + + + diff --git a/app/pages/application/submission/view/[id].vue b/app/pages/application/submission/view/[id].vue new file mode 100644 index 0000000..0a4857d --- /dev/null +++ b/app/pages/application/submission/view/[id].vue @@ -0,0 +1,189 @@ + + + diff --git a/pages/discord/callback.vue b/app/pages/discord/callback.vue similarity index 85% rename from pages/discord/callback.vue rename to app/pages/discord/callback.vue index 7435352..442c4a5 100644 --- a/pages/discord/callback.vue +++ b/app/pages/discord/callback.vue @@ -2,6 +2,7 @@ import { onMounted } from "vue"; const route = useRoute(); +const { refreshIdentity } = useSanctumAuth(); onMounted(async () => { const { error } = await useApi("/discord/callback", { @@ -12,6 +13,7 @@ onMounted(async () => { if (!error.value) { const returnUrl = localStorage.getItem("return"); localStorage.removeItem("return"); + await refreshIdentity(); return navigateTo(returnUrl ?? "/"); } else { return navigateTo("/login?noPermission"); @@ -20,6 +22,9 @@ onMounted(async () => { definePageMeta({ layout: "guest", + sanctum: { + guestOnly: true, + }, }); diff --git a/app/pages/faq/create.vue b/app/pages/faq/create.vue new file mode 100644 index 0000000..5cae856 --- /dev/null +++ b/app/pages/faq/create.vue @@ -0,0 +1,43 @@ + + + diff --git a/app/pages/faq/edit/[id].vue b/app/pages/faq/edit/[id].vue new file mode 100644 index 0000000..ae60d9c --- /dev/null +++ b/app/pages/faq/edit/[id].vue @@ -0,0 +1,52 @@ + + + diff --git a/app/pages/faq/index.vue b/app/pages/faq/index.vue new file mode 100644 index 0000000..c917b72 --- /dev/null +++ b/app/pages/faq/index.vue @@ -0,0 +1,94 @@ + + + diff --git a/app/pages/index.vue b/app/pages/index.vue new file mode 100644 index 0000000..29dc804 --- /dev/null +++ b/app/pages/index.vue @@ -0,0 +1,23 @@ + + + diff --git a/app/pages/login.vue b/app/pages/login.vue new file mode 100644 index 0000000..74806ef --- /dev/null +++ b/app/pages/login.vue @@ -0,0 +1,88 @@ + + + diff --git a/app/pages/logout.vue b/app/pages/logout.vue new file mode 100644 index 0000000..0d3ab0e --- /dev/null +++ b/app/pages/logout.vue @@ -0,0 +1,12 @@ + + + diff --git a/app/pages/permission/index.vue b/app/pages/permission/index.vue new file mode 100644 index 0000000..e254dbf --- /dev/null +++ b/app/pages/permission/index.vue @@ -0,0 +1,33 @@ + + + diff --git a/app/pages/profile.vue b/app/pages/profile.vue new file mode 100644 index 0000000..38922c6 --- /dev/null +++ b/app/pages/profile.vue @@ -0,0 +1,27 @@ + + + diff --git a/app/pages/reaction-role/create.vue b/app/pages/reaction-role/create.vue new file mode 100644 index 0000000..19df615 --- /dev/null +++ b/app/pages/reaction-role/create.vue @@ -0,0 +1,42 @@ + + + diff --git a/app/pages/reaction-role/edit/[id].vue b/app/pages/reaction-role/edit/[id].vue new file mode 100644 index 0000000..dcc553b --- /dev/null +++ b/app/pages/reaction-role/edit/[id].vue @@ -0,0 +1,51 @@ + + + diff --git a/app/pages/reaction-role/index.vue b/app/pages/reaction-role/index.vue new file mode 100644 index 0000000..3dbb6d4 --- /dev/null +++ b/app/pages/reaction-role/index.vue @@ -0,0 +1,110 @@ + + + diff --git a/app/pages/rule/create.vue b/app/pages/rule/create.vue new file mode 100644 index 0000000..e559639 --- /dev/null +++ b/app/pages/rule/create.vue @@ -0,0 +1,43 @@ + + + diff --git a/app/pages/rule/edit/[id].vue b/app/pages/rule/edit/[id].vue new file mode 100644 index 0000000..55a76ca --- /dev/null +++ b/app/pages/rule/edit/[id].vue @@ -0,0 +1,52 @@ + + + diff --git a/app/pages/rule/index.vue b/app/pages/rule/index.vue new file mode 100644 index 0000000..dbb0577 --- /dev/null +++ b/app/pages/rule/index.vue @@ -0,0 +1,98 @@ + + + diff --git a/app/pages/server-content/create.vue b/app/pages/server-content/create.vue new file mode 100644 index 0000000..6cf47e6 --- /dev/null +++ b/app/pages/server-content/create.vue @@ -0,0 +1,46 @@ + + + diff --git a/app/pages/server-content/edit/[id].vue b/app/pages/server-content/edit/[id].vue new file mode 100644 index 0000000..001755d --- /dev/null +++ b/app/pages/server-content/edit/[id].vue @@ -0,0 +1,52 @@ + + + diff --git a/app/pages/server-content/index.vue b/app/pages/server-content/index.vue new file mode 100644 index 0000000..15bea91 --- /dev/null +++ b/app/pages/server-content/index.vue @@ -0,0 +1,149 @@ + + + diff --git a/app/pages/server-content/message/index.vue b/app/pages/server-content/message/index.vue new file mode 100644 index 0000000..b4a576d --- /dev/null +++ b/app/pages/server-content/message/index.vue @@ -0,0 +1,52 @@ + + + diff --git a/app/pages/ticket/button/create.vue b/app/pages/ticket/button/create.vue new file mode 100644 index 0000000..1e6fe85 --- /dev/null +++ b/app/pages/ticket/button/create.vue @@ -0,0 +1,45 @@ + + + diff --git a/app/pages/ticket/button/edit/[id].vue b/app/pages/ticket/button/edit/[id].vue new file mode 100644 index 0000000..81671c3 --- /dev/null +++ b/app/pages/ticket/button/edit/[id].vue @@ -0,0 +1,53 @@ + + + diff --git a/app/pages/ticket/button/index.vue b/app/pages/ticket/button/index.vue new file mode 100644 index 0000000..d70ae03 --- /dev/null +++ b/app/pages/ticket/button/index.vue @@ -0,0 +1,106 @@ + + + diff --git a/app/pages/ticket/config/index.vue b/app/pages/ticket/config/index.vue new file mode 100644 index 0000000..e58626d --- /dev/null +++ b/app/pages/ticket/config/index.vue @@ -0,0 +1,37 @@ + + + diff --git a/app/pages/ticket/index.vue b/app/pages/ticket/index.vue new file mode 100644 index 0000000..d39f373 --- /dev/null +++ b/app/pages/ticket/index.vue @@ -0,0 +1,166 @@ + + + diff --git a/app/pages/ticket/panel/create.vue b/app/pages/ticket/panel/create.vue new file mode 100644 index 0000000..c40a446 --- /dev/null +++ b/app/pages/ticket/panel/create.vue @@ -0,0 +1,43 @@ + + + diff --git a/app/pages/ticket/panel/edit/[id].vue b/app/pages/ticket/panel/edit/[id].vue new file mode 100644 index 0000000..5ef7a9a --- /dev/null +++ b/app/pages/ticket/panel/edit/[id].vue @@ -0,0 +1,52 @@ + + + diff --git a/app/pages/ticket/panel/index.vue b/app/pages/ticket/panel/index.vue new file mode 100644 index 0000000..ebb8393 --- /dev/null +++ b/app/pages/ticket/panel/index.vue @@ -0,0 +1,113 @@ + + + diff --git a/app/pages/ticket/team/create.vue b/app/pages/ticket/team/create.vue new file mode 100644 index 0000000..8682b80 --- /dev/null +++ b/app/pages/ticket/team/create.vue @@ -0,0 +1,43 @@ + + + diff --git a/app/pages/ticket/team/edit/[id].vue b/app/pages/ticket/team/edit/[id].vue new file mode 100644 index 0000000..c580aaf --- /dev/null +++ b/app/pages/ticket/team/edit/[id].vue @@ -0,0 +1,53 @@ + + + diff --git a/app/pages/ticket/team/index.vue b/app/pages/ticket/team/index.vue new file mode 100644 index 0000000..5d19138 --- /dev/null +++ b/app/pages/ticket/team/index.vue @@ -0,0 +1,99 @@ + + + diff --git a/app/pages/ticket/transcript/[ticket_id].vue b/app/pages/ticket/transcript/[ticket_id].vue new file mode 100644 index 0000000..233b020 --- /dev/null +++ b/app/pages/ticket/transcript/[ticket_id].vue @@ -0,0 +1,121 @@ + + + diff --git a/public/favicon.ico b/app/public/favicon.ico similarity index 100% rename from public/favicon.ico rename to app/public/favicon.ico diff --git a/public/robots.txt b/app/public/robots.txt similarity index 100% rename from public/robots.txt rename to app/public/robots.txt diff --git a/types/discord.ts b/app/types/discord.ts similarity index 73% rename from types/discord.ts rename to app/types/discord.ts index c52467f..0637fbc 100644 --- a/types/discord.ts +++ b/app/types/discord.ts @@ -39,22 +39,6 @@ export type Role = { flags: number; }; -export type User = { - id: string; - username: string; - avatar: string; - discriminator: string; - public_flags: number; - flags: number; - banner?: string; - accent_color: number; - global_name: string; - avatar_decoration_data?: string; - banner_color: string; - clan?: string; - primary_guild?: string; -}; - export type GifAttachment = { video: { width: number; @@ -113,19 +97,3 @@ export type Embed = { color: number; fields: EmbedField[]; }; - -export type Member = { - avatar: string | null; - banner: string | null; - communication_disabled_until: string | null; - flags: number; - joined_at: string; - nick: string; - pending: boolean; - premium_since: string; - roles: Role["id"][]; - unusual_dm_activity_until: string; - user: User; - mute: boolean; - deaf: boolean; -}; diff --git a/app/types/form.ts b/app/types/form.ts new file mode 100644 index 0000000..90d1afa --- /dev/null +++ b/app/types/form.ts @@ -0,0 +1,16 @@ +export type LaravelValidationResponse = { + statusCode: number; + data: LaravelValidationErrors; +}; + +export type LaravelValidationErrors = { + errors: Record; + message: string; +}; + +export type NuxtUiFormError = { + name: string; // The path to the field with the error + message: string; // The error message +}; + +export type NuxtUiFormErrors = NuxtUiFormError[]; diff --git a/types/permission.ts b/app/types/permission.ts similarity index 57% rename from types/permission.ts rename to app/types/permission.ts index a3507bd..b169440 100644 --- a/types/permission.ts +++ b/app/types/permission.ts @@ -2,7 +2,12 @@ export type PermissionTemplate = { [key: string]: string[]; }; -export type PermissionMap = { +export type Permission = { role: string; permissions: string[]; }; + +export type PermissionMap = { + role: string; + permissions: Record>; +}; diff --git a/app/types/profile.ts b/app/types/profile.ts new file mode 100644 index 0000000..c9a4441 --- /dev/null +++ b/app/types/profile.ts @@ -0,0 +1,4 @@ +export type Profile = { + password: string; + password_confirmation: string; +}; diff --git a/types/response.ts b/app/types/response.ts similarity index 100% rename from types/response.ts rename to app/types/response.ts diff --git a/app/utils/discord.ts b/app/utils/discord.ts new file mode 100644 index 0000000..0301389 --- /dev/null +++ b/app/utils/discord.ts @@ -0,0 +1,76 @@ +import type { TextChannel, Role, Category } from "@/types/discord"; +import { DiscordButton } from "@OrdinarySMP/api-types"; +import type { SelectMenuItem } from "@nuxt/ui"; + +export const loadTextChannels = async (): Promise< + { label: string; value: string }[] +> => { + const client = useApiClient(); + const toast = useSimpleToast(); + + const response = await client("/discord/text-channels"); + + if (!response) { + toast.error("Could not load discord text channels!"); + } + + return ( + response + ?.map((channel): { label: string; value: string } => ({ + label: channel.name, + value: channel.id, + })) + .sort((a, b) => a.label.localeCompare(b.label)) ?? + ([] as { label: string; value: string }[]) + ); +}; + +export const loadRoles = async (): Promise< + { label: string; value: string }[] +> => { + const client = useApiClient(); + const toast = useSimpleToast(); + + const response = await client("/discord/roles"); + + if (!response) { + toast.error("Could not load discord roles!"); + } + + return ( + response?.map((role) => ({ + label: role.name, + value: role.id, + })) ?? ([] as { label: string; value: string }[]) + ); +}; + +export const loadCategories = async () => { + const client = useApiClient(); + const toast = useSimpleToast(); + + const response = await client("/discord/categories"); + + if (!response) { + toast.error("Could not load discord categories!"); + } + + return ( + response + ?.map((channel): { label: string; value: string } => ({ + label: channel.name, + value: channel.id, + })) + .sort((a, b) => a.label.localeCompare(b.label)) ?? + ([] as { label: string; value: string }[]) + ); +}; + +export const buttonOptions = (): SelectMenuItem[] => { + return Object.entries(DiscordButton) + .filter(([key, _value]) => isNaN(Number(key))) + .map(([key, value]) => ({ + label: key, + value: value, + })); +}; diff --git a/app/utils/helper.ts b/app/utils/helper.ts new file mode 100644 index 0000000..62384e3 --- /dev/null +++ b/app/utils/helper.ts @@ -0,0 +1,64 @@ +import type { LaravelValidationErrors, NuxtUiFormErrors } from "@/types/form"; + +export const parseRouteParameter = ( + param: string | string[] | undefined, +): number => { + if (typeof param === "object") { + const value = parseInt(param[0] ?? ""); + return Number.isNaN(value) ? 0 : value; + } + + const value = parseInt(param ?? ""); + return Number.isNaN(value) ? 0 : value; +}; + +export const hasPermissionTo = (permission: string): boolean => { + const user = useCurrentUser().value; + if (!user) { + return false; + } + return user.permissions.includes(permission) || user.is_owner; +}; + +// replace with enum from api +export const discordButtonItems = [ + { + label: "Primary", + value: 1, + color: "#5865f2", + }, + { + label: "Secondary", + value: 2, + color: "#4e5058", + }, + { + label: "Success", + value: 3, + color: "#248045", + }, + { + label: "Danger", + value: 4, + color: "#da373c", + }, +]; + +export function laravelValidationErrorToNuxtUiForm( + response: LaravelValidationErrors, +): NuxtUiFormErrors { + return Object.entries(response.errors).map(([name, messages]) => { + const baseName = name.split(".")[0]; + return { + name: baseName ?? "", + message: messages.join(" "), + }; + }); +} + +export const filterToQuery = (filter: Record) => + Object.fromEntries( + Object.entries(filter) + .filter(([_, v]) => v !== null && v !== undefined && v !== "") + .map(([k, v]) => [`filter[${k}]`, v]), + ); diff --git a/components/Accordion.vue b/components/Accordion.vue deleted file mode 100644 index 27d7e72..0000000 --- a/components/Accordion.vue +++ /dev/null @@ -1,51 +0,0 @@ - - - diff --git a/components/Button.vue b/components/Button.vue deleted file mode 100644 index f8033d2..0000000 --- a/components/Button.vue +++ /dev/null @@ -1,101 +0,0 @@ - - - diff --git a/components/Dialog.vue b/components/Dialog.vue deleted file mode 100644 index 9963087..0000000 --- a/components/Dialog.vue +++ /dev/null @@ -1,85 +0,0 @@ - - - diff --git a/components/Dropdown.vue b/components/Dropdown.vue deleted file mode 100644 index e2d9a7b..0000000 --- a/components/Dropdown.vue +++ /dev/null @@ -1,31 +0,0 @@ - - - diff --git a/components/Field/AddInput.vue b/components/Field/AddInput.vue deleted file mode 100644 index 27edfd4..0000000 --- a/components/Field/AddInput.vue +++ /dev/null @@ -1,91 +0,0 @@ - - - diff --git a/components/Field/Checkbox.vue b/components/Field/Checkbox.vue deleted file mode 100644 index 2f88483..0000000 --- a/components/Field/Checkbox.vue +++ /dev/null @@ -1,64 +0,0 @@ - - - diff --git a/components/Field/Input.vue b/components/Field/Input.vue deleted file mode 100644 index c3de318..0000000 --- a/components/Field/Input.vue +++ /dev/null @@ -1,98 +0,0 @@ - - - diff --git a/components/Field/MultiSelect.vue b/components/Field/MultiSelect.vue deleted file mode 100644 index a06c0e0..0000000 --- a/components/Field/MultiSelect.vue +++ /dev/null @@ -1,132 +0,0 @@ - - - diff --git a/components/Field/Select.vue b/components/Field/Select.vue deleted file mode 100644 index 933a5ad..0000000 --- a/components/Field/Select.vue +++ /dev/null @@ -1,129 +0,0 @@ - - - diff --git a/components/Field/Switch.vue b/components/Field/Switch.vue deleted file mode 100644 index 2296eff..0000000 --- a/components/Field/Switch.vue +++ /dev/null @@ -1,107 +0,0 @@ - - - diff --git a/components/Field/TextArea.vue b/components/Field/TextArea.vue deleted file mode 100644 index 6baea8f..0000000 --- a/components/Field/TextArea.vue +++ /dev/null @@ -1,57 +0,0 @@ - - -