mirror of
https://github.com/Arcadia-Solutions/arcadia.git
synced 2025-12-16 23:14:15 -06:00
feat: create forum category on frontend
This commit is contained in:
@@ -67,7 +67,9 @@
|
||||
"action": "Action | Actions",
|
||||
"default": "Default",
|
||||
"locked": "Locked",
|
||||
"sticky": "Sticky"
|
||||
"sticky": "Sticky",
|
||||
"save": "Save",
|
||||
"create": "Create"
|
||||
},
|
||||
"auth": {
|
||||
"remember_me": "Remember me"
|
||||
@@ -127,7 +129,10 @@
|
||||
"search": "Search forum",
|
||||
"post_edited_success": "Post edited successfully",
|
||||
"edit_thread": "Edit thread",
|
||||
"thread_edited_success": "Thread edited successfully"
|
||||
"thread_edited_success": "Thread edited successfully",
|
||||
"create_category": "Create forum category",
|
||||
"edit_category": "Edit forum category",
|
||||
"category_name": "Category name"
|
||||
},
|
||||
"user": {
|
||||
"username": "Username",
|
||||
@@ -448,6 +453,7 @@
|
||||
"password_mismatch": "Passwords do not match"
|
||||
},
|
||||
"error": {
|
||||
"field_required": "This field is required",
|
||||
"write_more_than_x_chars": "Write more than {0} characters",
|
||||
"enter_at_least_x_tags": "Enter at least {0} tags",
|
||||
"select_date": "Select a date",
|
||||
|
||||
@@ -165,6 +165,22 @@ const router = createRouter({
|
||||
},
|
||||
component: () => import('../views/forum/NewForumThreadView.vue'),
|
||||
},
|
||||
{
|
||||
path: '/forum/category/new',
|
||||
name: 'NewForumCategory',
|
||||
meta: {
|
||||
documentTitle: 'Create forum category',
|
||||
},
|
||||
component: () => import('../views/forum/CreateOrEditForumCategoryView.vue'),
|
||||
},
|
||||
{
|
||||
path: '/forum/category/:id/edit',
|
||||
name: 'EditForumCategory',
|
||||
meta: {
|
||||
documentTitle: 'Edit forum category',
|
||||
},
|
||||
component: () => import('../views/forum/CreateOrEditForumCategoryView.vue'),
|
||||
},
|
||||
{
|
||||
path: '/wiki/article/:id',
|
||||
name: 'WikiArticle',
|
||||
|
||||
@@ -344,6 +344,10 @@ export interface EditedCssSheet {
|
||||
'old_name': string;
|
||||
'preview_image_url': string;
|
||||
}
|
||||
export interface EditedForumCategory {
|
||||
'id': number;
|
||||
'name': string;
|
||||
}
|
||||
export interface EditedForumPost {
|
||||
'content': string;
|
||||
'id': number;
|
||||
@@ -556,6 +560,12 @@ export const Features = {
|
||||
export type Features = typeof Features[keyof typeof Features];
|
||||
|
||||
|
||||
export interface ForumCategory {
|
||||
'created_at': string;
|
||||
'created_by_id': number;
|
||||
'id': number;
|
||||
'name': string;
|
||||
}
|
||||
export interface ForumCategoryHierarchy {
|
||||
'id': number;
|
||||
'name': string;
|
||||
@@ -1388,6 +1398,7 @@ export interface Torrent {
|
||||
'trumpable'?: string | null;
|
||||
'updated_at': string;
|
||||
'upload_factor': number;
|
||||
'upload_method': string;
|
||||
'uploaded_as_anonymous': boolean;
|
||||
'video_codec'?: VideoCodec | null;
|
||||
'video_resolution'?: VideoResolution | null;
|
||||
@@ -1681,6 +1692,7 @@ export interface User {
|
||||
|
||||
|
||||
export interface UserApplication {
|
||||
'applied_from_ip': string;
|
||||
'body': string;
|
||||
'created_at': string;
|
||||
'email': string;
|
||||
@@ -1767,6 +1779,9 @@ export interface UserCreatedEditionGroup {
|
||||
}
|
||||
|
||||
|
||||
export interface UserCreatedForumCategory {
|
||||
'name': string;
|
||||
}
|
||||
export interface UserCreatedForumPost {
|
||||
'content': string;
|
||||
'forum_thread_id': number;
|
||||
@@ -4015,6 +4030,45 @@ export const getTMDBData = async (url: string, options?: RawAxiosRequestConfig):
|
||||
*/
|
||||
export const ForumApiAxiosParamCreator = function (configuration?: Configuration) {
|
||||
return {
|
||||
/**
|
||||
*
|
||||
* @param {UserCreatedForumCategory} userCreatedForumCategory
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
createForumCategory: async (userCreatedForumCategory: UserCreatedForumCategory, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'userCreatedForumCategory' is not null or undefined
|
||||
assertParamExists('createForumCategory', 'userCreatedForumCategory', userCreatedForumCategory)
|
||||
const localVarPath = `/api/forum/category`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication http required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||
|
||||
|
||||
|
||||
localVarHeaderParameter['Content-Type'] = 'application/json';
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(userCreatedForumCategory, localVarRequestOptions, configuration)
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {UserCreatedForumPost} userCreatedForumPost
|
||||
@@ -4093,6 +4147,45 @@ export const ForumApiAxiosParamCreator = function (configuration?: Configuration
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {EditedForumCategory} editedForumCategory
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
editForumCategory: async (editedForumCategory: EditedForumCategory, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'editedForumCategory' is not null or undefined
|
||||
assertParamExists('editForumCategory', 'editedForumCategory', editedForumCategory)
|
||||
const localVarPath = `/api/forum/category`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'PUT', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication http required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||
|
||||
|
||||
|
||||
localVarHeaderParameter['Content-Type'] = 'application/json';
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(editedForumCategory, localVarRequestOptions, configuration)
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {EditedForumPost} editedForumPost
|
||||
@@ -4330,6 +4423,18 @@ export const ForumApiAxiosParamCreator = function (configuration?: Configuration
|
||||
export const ForumApiFp = function(configuration?: Configuration) {
|
||||
const localVarAxiosParamCreator = ForumApiAxiosParamCreator(configuration)
|
||||
return {
|
||||
/**
|
||||
*
|
||||
* @param {UserCreatedForumCategory} userCreatedForumCategory
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async createForumCategory(userCreatedForumCategory: UserCreatedForumCategory, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<ForumCategory>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.createForumCategory(userCreatedForumCategory, options);
|
||||
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||
const localVarOperationServerBasePath = operationServerMap['ForumApi.createForumCategory']?.[localVarOperationServerIndex]?.url;
|
||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {UserCreatedForumPost} userCreatedForumPost
|
||||
@@ -4354,6 +4459,18 @@ export const ForumApiFp = function(configuration?: Configuration) {
|
||||
const localVarOperationServerBasePath = operationServerMap['ForumApi.createForumThread']?.[localVarOperationServerIndex]?.url;
|
||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {EditedForumCategory} editedForumCategory
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async editForumCategory(editedForumCategory: EditedForumCategory, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<ForumCategory>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.editForumCategory(editedForumCategory, options);
|
||||
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||
const localVarOperationServerBasePath = operationServerMap['ForumApi.editForumCategory']?.[localVarOperationServerIndex]?.url;
|
||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {EditedForumPost} editedForumPost
|
||||
@@ -4437,6 +4554,15 @@ export const ForumApiFp = function(configuration?: Configuration) {
|
||||
export const ForumApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
|
||||
const localVarFp = ForumApiFp(configuration)
|
||||
return {
|
||||
/**
|
||||
*
|
||||
* @param {UserCreatedForumCategory} userCreatedForumCategory
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
createForumCategory(userCreatedForumCategory: UserCreatedForumCategory, options?: RawAxiosRequestConfig): AxiosPromise<ForumCategory> {
|
||||
return localVarFp.createForumCategory(userCreatedForumCategory, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {UserCreatedForumPost} userCreatedForumPost
|
||||
@@ -4455,6 +4581,15 @@ export const ForumApiFactory = function (configuration?: Configuration, basePath
|
||||
createForumThread(userCreatedForumThread: UserCreatedForumThread, options?: RawAxiosRequestConfig): AxiosPromise<ForumThread> {
|
||||
return localVarFp.createForumThread(userCreatedForumThread, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {EditedForumCategory} editedForumCategory
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
editForumCategory(editedForumCategory: EditedForumCategory, options?: RawAxiosRequestConfig): AxiosPromise<ForumCategory> {
|
||||
return localVarFp.editForumCategory(editedForumCategory, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {EditedForumPost} editedForumPost
|
||||
@@ -4518,6 +4653,16 @@ export const ForumApiFactory = function (configuration?: Configuration, basePath
|
||||
* ForumApi - object-oriented interface
|
||||
*/
|
||||
export class ForumApi extends BaseAPI {
|
||||
/**
|
||||
*
|
||||
* @param {UserCreatedForumCategory} userCreatedForumCategory
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
public createForumCategory(userCreatedForumCategory: UserCreatedForumCategory, options?: RawAxiosRequestConfig) {
|
||||
return ForumApiFp(this.configuration).createForumCategory(userCreatedForumCategory, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {UserCreatedForumPost} userCreatedForumPost
|
||||
@@ -4538,6 +4683,16 @@ export class ForumApi extends BaseAPI {
|
||||
return ForumApiFp(this.configuration).createForumThread(userCreatedForumThread, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {EditedForumCategory} editedForumCategory
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
public editForumCategory(editedForumCategory: EditedForumCategory, options?: RawAxiosRequestConfig) {
|
||||
return ForumApiFp(this.configuration).editForumCategory(editedForumCategory, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {EditedForumPost} editedForumPost
|
||||
@@ -4606,6 +4761,12 @@ export const forumApi = new ForumApi(undefined, undefined, globalAxios);
|
||||
|
||||
|
||||
|
||||
export const createForumCategory = async (userCreatedForumCategory: UserCreatedForumCategory, options?: RawAxiosRequestConfig): Promise<ForumCategory> => {
|
||||
const response = await forumApi.createForumCategory(userCreatedForumCategory, options);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
|
||||
export const createForumPost = async (userCreatedForumPost: UserCreatedForumPost, options?: RawAxiosRequestConfig): Promise<ForumPost> => {
|
||||
const response = await forumApi.createForumPost(userCreatedForumPost, options);
|
||||
return response.data;
|
||||
@@ -4618,6 +4779,12 @@ export const createForumThread = async (userCreatedForumThread: UserCreatedForum
|
||||
};
|
||||
|
||||
|
||||
export const editForumCategory = async (editedForumCategory: EditedForumCategory, options?: RawAxiosRequestConfig): Promise<ForumCategory> => {
|
||||
const response = await forumApi.editForumCategory(editedForumCategory, options);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
|
||||
export const editForumPost = async (editedForumPost: EditedForumPost, options?: RawAxiosRequestConfig): Promise<ForumPost> => {
|
||||
const response = await forumApi.editForumPost(editedForumPost, options);
|
||||
return response.data;
|
||||
|
||||
93
frontend/src/views/forum/CreateOrEditForumCategoryView.vue
Normal file
93
frontend/src/views/forum/CreateOrEditForumCategoryView.vue
Normal file
@@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<ContentContainer :title="isEditMode ? t('forum.edit_category') : t('forum.create_category')">
|
||||
<Form v-slot="$form" :initialValues="formData" :resolver @submit="onFormSubmit">
|
||||
<FloatLabel variant="in">
|
||||
<InputText v-model="formData.name" name="name" :class="{ 'p-invalid': $form.name?.invalid }" />
|
||||
<label for="name">{{ t('forum.category_name') }}</label>
|
||||
</FloatLabel>
|
||||
<Message v-if="$form.name?.invalid" severity="error">
|
||||
{{ $form.name.error?.message }}
|
||||
</Message>
|
||||
|
||||
<div class="actions">
|
||||
<Button type="submit" :label="isEditMode ? t('general.save') : t('general.create')" :loading="loading" />
|
||||
</div>
|
||||
</Form>
|
||||
</ContentContainer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { Button, FloatLabel, InputText, Message } from 'primevue'
|
||||
import { Form, type FormResolverOptions, type FormSubmitEvent } from '@primevue/forms'
|
||||
import ContentContainer from '@/components/ContentContainer.vue'
|
||||
import { createForumCategory, editForumCategory, getForum, type EditedForumCategory, type UserCreatedForumCategory } from '@/services/api-schema/api'
|
||||
import { showToast } from '@/main'
|
||||
|
||||
const { t } = useI18n()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const isEditMode = computed(() => route.path.includes('/edit'))
|
||||
const loading = ref(false)
|
||||
const formData = ref<UserCreatedForumCategory | EditedForumCategory>({
|
||||
name: '',
|
||||
})
|
||||
|
||||
const resolver = ({ values }: FormResolverOptions) => {
|
||||
const errors: Partial<Record<keyof UserCreatedForumCategory, { message: string }[]>> = {}
|
||||
|
||||
if (!values.name || values.name.trim().length === 0) {
|
||||
errors.name = [{ message: t('error.field_required') }]
|
||||
} else if (values.name.trim().length < 2) {
|
||||
errors.name = [{ message: t('error.write_more_than_x_chars', [1]) }]
|
||||
}
|
||||
|
||||
return { errors }
|
||||
}
|
||||
|
||||
const onFormSubmit = async ({ valid }: FormSubmitEvent) => {
|
||||
if (!valid) return
|
||||
loading.value = true
|
||||
try {
|
||||
if (isEditMode.value) {
|
||||
await editForumCategory(formData.value as EditedForumCategory)
|
||||
} else {
|
||||
await createForumCategory(formData.value as UserCreatedForumCategory)
|
||||
}
|
||||
router.push('/forum')
|
||||
} catch {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
if (isEditMode.value) {
|
||||
const categoryId = Number(route.params.id)
|
||||
|
||||
// Fetch forum overview to get the category data
|
||||
const forumOverview = await getForum()
|
||||
const category = forumOverview.forum_categories.find((cat) => cat.id === categoryId)
|
||||
|
||||
if (category) {
|
||||
formData.value = {
|
||||
id: category.id,
|
||||
name: category.name,
|
||||
}
|
||||
} else {
|
||||
showToast('', 'forum category not found', 'error', 2000)
|
||||
router.push('/forum')
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.actions {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -13,6 +13,9 @@
|
||||
<RouterLink to="/forum/search">
|
||||
<i class="pi pi-search" v-tooltip.top="t('forum.search')" />
|
||||
</RouterLink>
|
||||
<RouterLink to="/forum/category/new" v-if="userStore.class === 'staff'">
|
||||
<i class="pi pi-plus" v-tooltip.top="t('forum.create_category')" />
|
||||
</RouterLink>
|
||||
</div>
|
||||
<ForumCategoryOverview class="forum-category" v-for="category in forumOverview.forum_categories" :key="category.id" :forum-category="category" />
|
||||
</div>
|
||||
@@ -27,8 +30,10 @@ import ContentContainer from '@/components/ContentContainer.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { getForum, type ForumOverview } from '@/services/api-schema'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
|
||||
const { t } = useI18n()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const forumOverview = ref<null | ForumOverview>(null)
|
||||
|
||||
@@ -44,6 +49,7 @@ onMounted(async () => {
|
||||
justify-content: center;
|
||||
> a {
|
||||
margin: 0 10px;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
.forum-category {
|
||||
|
||||
Reference in New Issue
Block a user