Files
CRM_Montzar/apps/web/src/views/ProjectCardFormView.vue
T

166 lines
3.9 KiB
Vue
Raw Normal View History

<script setup lang="ts">
import { computed, onMounted, ref } from 'vue';
import { RouterLink, useRoute, useRouter } from 'vue-router';
import axios from 'axios';
import { api } from '@/lib/api';
import type { ProjectCardDto } from '@mento/shared';
const route = useRoute();
const router = useRouter();
const isNew = computed(() => route.name === 'project-card-new');
const loading = ref(false);
const saving = ref(false);
const error = ref('');
const title = ref('');
const notes = ref('');
const cardId = ref('');
async function load() {
if (isNew.value) return;
const id = String(route.params.id || '');
if (!id) return;
loading.value = true;
error.value = '';
try {
const { data } = await api.get<ProjectCardDto>(`/project-cards/${id}`);
cardId.value = data.id;
title.value = data.title;
notes.value = data.notes ?? '';
} catch (e) {
if (axios.isAxiosError(e) && !e.response) {
error.value = 'اتصال به API برقرار نشد.';
} else {
error.value = 'بارگذاری کارت ناموفق بود.';
}
} finally {
loading.value = false;
}
}
async function save() {
if (title.value.trim().length < 2 || saving.value) return;
saving.value = true;
error.value = '';
try {
if (isNew.value) {
const boardId =
typeof route.query.boardId === 'string' ? route.query.boardId : undefined;
const { data } = await api.post<ProjectCardDto>('/project-cards', {
title: title.value.trim(),
notes: notes.value.trim() || undefined,
boardId,
});
await router.replace({ name: 'project-card-detail', params: { id: data.id } });
} else {
await api.patch(`/project-cards/${cardId.value}`, {
title: title.value.trim(),
notes: notes.value.trim() || null,
});
}
} catch {
error.value = 'ذخیره کارت ناموفق بود.';
} finally {
saving.value = false;
}
}
async function removeCard() {
if (isNew.value || !cardId.value) return;
if (!confirm('کارت حذف شود؟')) return;
try {
await api.delete(`/project-cards/${cardId.value}`);
await router.push({ name: 'projects' });
} catch {
error.value = 'حذف کارت ناموفق بود.';
}
}
onMounted(load);
</script>
<template>
<section class="page">
<header class="page-head">
<div>
<RouterLink class="back" :to="{ name: 'projects' }">← بازگشت به برد</RouterLink>
<h1>{{ isNew ? 'کارت جدید' : 'ویرایش کارت' }}</h1>
</div>
</header>
<p v-if="error" class="error">{{ error }}</p>
<p v-else-if="loading" class="muted">در حال بارگذاری…</p>
<form v-else class="form" @submit.prevent="save">
<label>
عنوان
<input v-model="title" type="text" required minlength="2" maxlength="200" />
</label>
<label>
یادداشت
<textarea v-model="notes" rows="5" maxlength="4000" />
</label>
<div class="actions">
<button class="btn" type="submit" :disabled="saving || title.trim().length < 2">
{{ saving ? 'در حال ذخیره…' : 'ذخیره' }}
</button>
<button
v-if="!isNew"
class="btn btn-ghost danger"
type="button"
@click="removeCard"
>
حذف
</button>
</div>
</form>
</section>
</template>
<style scoped>
.page {
display: grid;
gap: 1rem;
max-width: 640px;
}
.back {
color: var(--muted);
text-decoration: none;
font-size: 0.9rem;
}
h1 {
margin: 0.35rem 0 0;
}
.form {
display: grid;
gap: 0.85rem;
}
label {
display: grid;
gap: 0.35rem;
color: var(--muted);
font-size: 0.9rem;
}
input,
textarea {
border: 1px solid var(--line);
border-radius: 12px;
padding: 0.7rem 0.85rem;
font: inherit;
color: var(--ink);
}
.actions {
display: flex;
gap: 0.5rem;
}
.error {
color: #b42318;
}
.muted {
color: var(--muted);
}
.danger {
color: #b42318;
}
</style>