Added pretty much everything except discussion forums
This commit is contained in:
241
ui/src/components/modRequests/ModRequestForm.vue
Normal file
241
ui/src/components/modRequests/ModRequestForm.vue
Normal file
@@ -0,0 +1,241 @@
|
||||
<script setup lang="ts">
|
||||
import { ModRequestSchema } from '@shared/schemas/modRequest'
|
||||
import { useForm, Field as VeeField } from 'vee-validate'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import { ref } from 'vue'
|
||||
import Button from '@/components/ui/button/Button.vue'
|
||||
import Field from '@/components/ui/field/Field.vue'
|
||||
import FieldLabel from '@/components/ui/field/FieldLabel.vue'
|
||||
import FieldError from '@/components/ui/field/FieldError.vue'
|
||||
import FieldDescription from '@/components/ui/field/FieldDescription.vue'
|
||||
import Input from '@/components/ui/input/Input.vue'
|
||||
import Textarea from '@/components/ui/textarea/Textarea.vue'
|
||||
import Checkbox from '@/components/ui/checkbox/Checkbox.vue'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import { X } from 'lucide-vue-next'
|
||||
import { postModRequest } from '@/api/modRequests'
|
||||
|
||||
const { handleSubmit, resetForm, errors } = useForm({
|
||||
validationSchema: toTypedSchema(ModRequestSchema),
|
||||
validateOnMount: false,
|
||||
initialValues: {
|
||||
mod_title: '',
|
||||
description: '',
|
||||
mod_link: '',
|
||||
confirmed_tested: false,
|
||||
reason: '',
|
||||
detrimental_effects: '',
|
||||
keybind_conflicts: '',
|
||||
special_considerations: '',
|
||||
},
|
||||
})
|
||||
|
||||
const submitting = ref(false)
|
||||
const emit = defineEmits(['submit', 'close'])
|
||||
|
||||
const submitForm = handleSubmit(async (values) => {
|
||||
if (submitting.value) return
|
||||
submitting.value = true
|
||||
try {
|
||||
await postModRequest(values);
|
||||
emit('submit', values)
|
||||
} catch (err) {
|
||||
console.error('Error submitting mod request:', err)
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Card class="border-0 shadow-sm">
|
||||
<CardHeader>
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="flex-1">
|
||||
<CardTitle>New Mod Request</CardTitle>
|
||||
<CardDescription>Share details about the mod you'd like to see added to our server</CardDescription>
|
||||
</div>
|
||||
<Button type="button" variant="ghost" @click="emit('close')"
|
||||
class="text-muted-foreground hover:text-foreground -mt-1 -mr-2">
|
||||
Back to posts <X></X>
|
||||
</Button>
|
||||
</div>
|
||||
</CardHeader>
|
||||
|
||||
<Separator class="mb-0" />
|
||||
|
||||
<CardContent>
|
||||
<form @submit.prevent="submitForm" class="space-y-8">
|
||||
<!-- SECTION: Basic Mod Information -->
|
||||
<div class="space-y-5">
|
||||
<div class="space-y-1">
|
||||
<h3 class="font-semibold text-sm text-foreground">Mod Information</h3>
|
||||
<p class="text-xs text-muted-foreground">Core details about the mod</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-5">
|
||||
<!-- Title -->
|
||||
<VeeField name="mod_title" v-slot="{ field, errors: e }">
|
||||
<Field :data-invalid="!!e.length">
|
||||
<FieldLabel class="text-sm font-medium">Mod Title</FieldLabel>
|
||||
<Input v-bind="field" placeholder="Name of the mod" rows="4" class="resize-none mt-2" />
|
||||
<div class="h-4">
|
||||
<FieldError v-if="e.length" :errors="e" />
|
||||
</div>
|
||||
</Field>
|
||||
</VeeField>
|
||||
|
||||
<!-- Description -->
|
||||
<VeeField name="description" v-slot="{ field, errors: e }">
|
||||
<Field :data-invalid="!!e.length">
|
||||
<FieldLabel class="text-sm font-medium">What is this mod?</FieldLabel>
|
||||
<FieldDescription class="text-xs">Brief overview of the mod and its main functionality
|
||||
</FieldDescription>
|
||||
<Textarea v-bind="field" placeholder="Describe what this mod does..." rows="4"
|
||||
class="resize-none mt-2" />
|
||||
<div class="h-4">
|
||||
<FieldError v-if="e.length" :errors="e" />
|
||||
</div>
|
||||
</Field>
|
||||
</VeeField>
|
||||
|
||||
<!-- Mod Link -->
|
||||
<VeeField name="mod_link" v-slot="{ field, errors: e }">
|
||||
<Field :data-invalid="!!e.length">
|
||||
<FieldLabel class="text-sm font-medium">Mod Link</FieldLabel>
|
||||
<FieldDescription class="text-xs">Where can this mod be found?</FieldDescription>
|
||||
<Input v-bind="field" placeholder="https://..." class="mt-2" />
|
||||
<div class="h-4">
|
||||
<FieldError v-if="e.length" :errors="e" />
|
||||
</div>
|
||||
</Field>
|
||||
</VeeField>
|
||||
|
||||
<!-- Reason -->
|
||||
<VeeField name="reason" v-slot="{ field, errors: e }">
|
||||
<Field :data-invalid="!!e.length">
|
||||
<FieldLabel class="text-sm font-medium">Why add this mod?</FieldLabel>
|
||||
<FieldDescription class="text-xs">What benefits does this mod bring to our community and
|
||||
why should we consider it?
|
||||
</FieldDescription>
|
||||
<Textarea v-bind="field" placeholder="Share your thoughts..." rows="3"
|
||||
class="resize-none mt-2" />
|
||||
<div class="h-4">
|
||||
<FieldError v-if="e.length" :errors="e" />
|
||||
</div>
|
||||
</Field>
|
||||
</VeeField>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<!-- SECTION: Testing & Verification -->
|
||||
<div class="space-y-5">
|
||||
<div class="space-y-1">
|
||||
<h3 class="font-semibold text-sm text-foreground">Testing & Verification</h3>
|
||||
<p class="text-xs text-muted-foreground">Your experience with this mod</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-5">
|
||||
<!-- Confirmed Tested -->
|
||||
<VeeField name="confirmed_tested" v-slot="{ field, errors: e }">
|
||||
<Field :data-invalid="!!e.length">
|
||||
<div class="flex items-center gap-3 p-3 rounded-md bg-muted/30 border border-border/50">
|
||||
<Checkbox :model-value="field.value" @update:model-value="field.onChange"
|
||||
class="hover:cursor-pointer" />
|
||||
<div class="flex-1">
|
||||
<FieldLabel class="font-medium text-md cursor-pointer">Testing & Stability
|
||||
Confirmation
|
||||
</FieldLabel>
|
||||
<FieldDescription class="text-sm">I confirm that I have personally tested this
|
||||
mod and to the best of my ability have verified that it functions as
|
||||
described without
|
||||
causing game-breaking bugs,
|
||||
critical stability issues, or unintended performance degradation.
|
||||
</FieldDescription>
|
||||
</div>
|
||||
</div>
|
||||
<div class="h-4">
|
||||
<FieldError v-if="e.length" :errors="e" />
|
||||
</div>
|
||||
</Field>
|
||||
</VeeField>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<!-- SECTION: Compatibility -->
|
||||
<div class="space-y-5">
|
||||
<div class="space-y-1">
|
||||
<h3 class="font-semibold text-sm text-foreground">Compatibility & Conflicts</h3>
|
||||
<p class="text-xs text-muted-foreground">How does it work with our current setup?</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-5">
|
||||
<!-- Detrimental Effects -->
|
||||
<VeeField name="detrimental_effects" v-slot="{ field, errors: e }">
|
||||
<Field :data-invalid="!!e.length">
|
||||
<FieldLabel class="text-sm font-medium">Potential Issues</FieldLabel>
|
||||
<FieldDescription class="text-xs">Any negative impacts or concerns you noticed (Keybind
|
||||
conflicts sould be noted in the dedicated section)?
|
||||
</FieldDescription>
|
||||
<Textarea v-bind="field" placeholder="List any issues... (leave blank if none)" rows="3"
|
||||
class="resize-none mt-2" />
|
||||
<div class="h-4">
|
||||
<FieldError v-if="e.length" :errors="e" />
|
||||
</div>
|
||||
</Field>
|
||||
</VeeField>
|
||||
|
||||
<!-- Keybind Conflicts -->
|
||||
<VeeField name="keybind_conflicts" v-slot="{ field, errors: e }">
|
||||
<Field :data-invalid="!!e.length">
|
||||
<FieldLabel class="text-sm font-medium">Keybind Conflicts</FieldLabel>
|
||||
<FieldDescription class="text-xs">Identify any controls that conflict with the existing
|
||||
modpack along with resolutions for those conflicts.
|
||||
</FieldDescription>
|
||||
<Textarea v-bind="field"
|
||||
placeholder='List specific conflicts and resolutions here, or type "None" if there are no conflicts.'
|
||||
rows="3" class="resize-none mt-2" />
|
||||
<div class="h-4">
|
||||
<FieldError v-if="e.length" :errors="e" />
|
||||
</div>
|
||||
</Field>
|
||||
</VeeField>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<!-- SECTION: Additional Notes -->
|
||||
<div class="space-y-5">
|
||||
<div class="space-y-5">
|
||||
<!-- Special Considerations -->
|
||||
<VeeField name="special_considerations" v-slot="{ field, errors: e }">
|
||||
<Field :data-invalid="!!e.length">
|
||||
<FieldLabel class="text-sm font-medium">Additional Information</FieldLabel>
|
||||
<FieldDescription class="text-xs">Anything else we should know?</FieldDescription>
|
||||
<Textarea v-bind="field" placeholder="Add any other important notes... (optional)"
|
||||
rows="4" class="resize-none mt-2" />
|
||||
<div class="h-4">
|
||||
<FieldError v-if="e.length" :errors="e" />
|
||||
</div>
|
||||
</Field>
|
||||
</VeeField>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="flex gap-2 justify-end pt-4">
|
||||
<Button type="button" variant="outline" @click="resetForm">Clear</Button>
|
||||
<Button type="submit" :disabled="submitting">
|
||||
{{ submitting ? 'Submitting...' : 'Submit Request' }}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</template>
|
||||
Reference in New Issue
Block a user