Page design for darta chalani frontend

This commit is contained in:
achalise 2025-12-15 12:28:51 +05:45
parent fef301045e
commit c50e0242bf
5 changed files with 364 additions and 107 deletions

View File

@ -13,18 +13,17 @@
/> />
</template> </template>
</ContentLayout> </ContentLayout>
<Create /> <CreateChalani />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, watch } from "vue"; import { ref } from "vue";
import { BStoAD, NepaliDate } from "nepali-date-library"; import { BStoAD, NepaliDate } from "nepali-date-library";
import { storeToRefs } from "pinia"; import { storeToRefs } from "pinia";
import Create from "@/views/Chalani/Create.vue"; import CreateChalani from "@/views/Chalani/CreateChalani.vue";
import { createGenericStore } from "@/stores/GenericStore"; import { createGenericStore } from "@/stores/GenericStore";
import { createOverlayStore } from "@/stores/OverlayStore"; import { createOverlayStore } from "@/stores/OverlayStore";
import { Toast } from "dolphin-components";
const ChalaniStore = createGenericStore("chalani")(); const ChalaniStore = createGenericStore("chalani")();
const ChalaniTowserStore = createOverlayStore("chalani-towser")(); const ChalaniTowserStore = createOverlayStore("chalani-towser")();
@ -52,7 +51,7 @@ const dateRange = ref({
isBS: true, isBS: true,
}); });
const selectedDate = ref(BStoAD(new NepaliDate().format("YYYY-MM-DD"))); // const selectedDate = ref(BStoAD(new NepaliDate().format("YYYY-MM-DD")));
const headerDetails = [ const headerDetails = [
{ {

View File

@ -1,44 +0,0 @@
<template>
<!-- <Modal :title="modal.title" :actions="modal.action" @onClose="onClose"></Modal> -->
<Towser
:show="ChalaniTowserStore.show"
:title="towser.title"
:actions="towser.action"
@onClose="onClose"
>
</Towser>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { createGenericStore } from "@/stores/GenericStore";
import { createOverlayStore } from "@/stores/OverlayStore";
const ChalaniStore = createGenericStore("user-meal-schedule")();
const ChalaniTowserStore = createOverlayStore("chalani-towser")();
const towser = ref({
show: false,
title: [
{
name: "Chalani",
link: "#",
},
{
name: "Create",
},
],
action: [
{
title: "Close",
emit: "onClose",
class: "btn-outline",
},
{
title: "Save",
emit: "onSave",
},
],
});
const onClose = () => {};
</script>

View File

@ -0,0 +1,245 @@
<template>
<Towser :show="show" :title="towser.title" :actions="towser.action" @onClose="onClose" @onSave="onSave">
<div class="p-4 space-y-6">
<div>
<h2 class="font-semibold mb-4">Document Details</h2>
<div class="grid grid-cols-3 gap-x-[5px] gap-y-[15px] mb-4">
<div class="">
<label class="">
Department
<span class="text-red-500">*</span>
</label>
<Multiselect
v-model="formData.department"
:options="departments"
:multiple="false"
:searchable="true"
:allow-empty="false"
:show-labels="false"
label="name"
track-by="id"
placeholder="Select Department"
/>
</div>
<div class="">
<label class="">
Category
<span class="text-red-500">*</span>
</label>
<Multiselect
v-model="formData.documentCategory"
:options="documentCategories"
:multiple="false"
:searchable="true"
:allow-empty="false"
:show-labels="false"
label="name"
track-by="id"
placeholder="Select Category"
/>
</div>
<div class="">
<div class="flex flex-col">
<label class="">
Document Number
<span class="text-red-500">*</span>
</label>
<input
v-model="formData.documentNumber"
type="text"
placeholder="Enter document number"
class="form-input"
/>
</div>
</div>
</div>
<div class="grid grid-cols-2 gap-x-[5px] gap-y-[15px]">
<div class="flex flex-col">
<label class="">
Subject
<span class="text-red-500">*</span>
</label>
<input
v-model="formData.subject"
type="text"
placeholder="Enter document subject"
class="form-input"
/>
</div>
<div class="flex flex-col">
<label class="">
Body
<span class="text-red-500">*</span>
</label>
<input
v-model="formData.subject"
type="text"
placeholder="Enter document subject"
class="form-input"
/>
</div>
</div>
</div>
<div>
<h2 class="font-semibold mb-4">Receipent Information</h2>
<div class="grid grid-cols-3 gap-x-[5px] gap-y-[15px]">
<div class="flex flex-col">
<label class="">Recipient Name</label>
<input
v-model="formData.recipientName"
type="text"
placeholder="Enter Receipant Informtion"
class="form-input"
/>
</div>
<div class="flex flex-col">
<label class="">Recipient Contact</label>
<input
v-model="formData.recipientContact"
type="tel"
class="form-input"
placeholder="Enter Receipant Contact Information"
/>
</div>
<div class="flex flex-col">
<label class="">Receipant Address</label>
<input
v-model="formData.recipientAddress"
type="text"
class="form-input"
placeholder="Enter Receipant address Information"
/>
</div>
</div>
</div>
<div>
<h2 class="text-base font-semibold mb-4">Attachments</h2>
<div class="border-2 border-dashed p-6 text-center cursor-pointer" @click="triggerFileInput">
<input
type="file"
multiple
@change="handleFileUpload"
class="hidden"
ref="fileInputRef"
accept=".pdf,.doc,.docx,.xls,.xlsx,.jpg,.png"
/>
<p class="text-sm mb-2">Click to upload or drag and drop</p>
<div v-if="formData.attachments.length > 0" class="mt-4 text-left">
<ul class="space-y-2">
<li
v-for="(file, index) in formData.attachments"
:key="index"
class="flex justify-between items-center border p-2"
>
<span class="text-sm truncate">{{ file.name }}</span>
<button type="button" @click.stop="removeFile(index)" class="text-sm">Remove</button>
</li>
</ul>
</div>
</div>
</div>
<div>
<div class="grid grid-cols-3 gap-x-[5px] gap-y-[15px]">
<div class="flex flex-col">
<label class="">Issued Date</label>
<input v-model="formData.issuedDate" type="date" class="form-input" />
</div>
<div class="flex flex-col">
<label class="">Dispatch Date</label>
<input v-model="formData.dispatchDate" type="date" class="form-input" />
</div>
</div>
</div>
</div>
</Towser>
</template>
<script setup lang="ts">
import { ref, reactive } from "vue";
import { storeToRefs } from "pinia";
import { createOverlayStore } from "@/stores/OverlayStore";
import Multiselect from "vue-multiselect";
const ChalaniTowserStore = createOverlayStore("chalani-towser")();
const { show } = storeToRefs(ChalaniTowserStore);
const fileInputRef = ref<HTMLInputElement | null>(null);
const towser = ref({
title: [{ name: "Chalani", link: "#" }, { name: "Create" }],
action: [
{
title: "Close",
emit: "onClose",
},
{
title: "Save",
emit: "onSave",
},
],
});
const formData = reactive({
department: null,
documentCategory: null,
documentNumber: "",
subject: "",
body: "",
recipientName: "",
recipientContact: "",
recipientAddress: "",
issuedDate: "",
dispatchDate: "",
attachments: [] as File[],
});
const departments = ref([
{ id: 1, name: "Administration" },
{ id: 2, name: "HR" },
]);
const documentCategories = ref([
{ id: 1, name: "Confidential" },
{ id: 2, name: "Public" },
]);
const resetForm = () => {
formData.documentNumber = "";
formData.subject = "";
formData.attachments = [];
};
const onClose = () => {
ChalaniTowserStore.close();
resetForm();
};
const removeFile = (index: number) => {
formData.attachments.splice(index, 1);
};
const onSave = () => {
submitForm();
};
const submitForm = async () => {
console.log("Submitting:", formData);
onClose();
};
const triggerFileInput = () => {
fileInputRef.value?.click();
};
const handleFileUpload = (event: Event) => {
const target = event.target as HTMLInputElement;
if (target.files) {
formData.attachments = [...formData.attachments, ...Array.from(target.files)];
}
};
</script>

View File

@ -1,19 +1,15 @@
<template> <template>
<Towser <Towser :show="show" :title="towser.title" :actions="towser.action" @onClose="onClose" @onSave="onSave">
:show="show" <div class="p-4">
:title="towser.title" <div>
:actions="towser.action" <div class="mb-5">
:width="800" <h2 class="text-base font-semibold mb-3">Document Details</h2>
@onClose="onClose"
@onSave="onSave"
>
<div class="p-6">
<form @submit.prevent="submitForm">
<div class="mb-8">
<h2 class="text-lg font-semibold text-gray-700 mb-4">Document Details</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="flex flex-col"> <div class="">
<label class="block text-sm font-medium text-gray-700 mb-2">Department <span class="text-red-500">*</span></label> <label class="block text-sm font-medium mb-2">
Department
<span class="text-red-500">*</span>
</label>
<Multiselect <Multiselect
v-model="formData.department" v-model="formData.department"
:options="departments" :options="departments"
@ -26,7 +22,10 @@
/> />
</div> </div>
<div class="flex flex-col"> <div class="flex flex-col">
<label class="block text-sm font-medium text-gray-700 mb-2">Category <span class="text-red-500">*</span></label> <label class="block text-sm font-medium mb-2">
Category
<span class="text-red-500">*</span>
</label>
<Multiselect <Multiselect
v-model="formData.documentCategory" v-model="formData.documentCategory"
:options="documentCategories" :options="documentCategories"
@ -42,34 +41,58 @@
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-6"> <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-6">
<div class="flex flex-col"> <div class="flex flex-col">
<label class="block text-sm font-medium text-gray-700 mb-2">Document Number <span class="text-red-500">*</span></label> <label class="block text-sm font-medium mb-2">
<input v-model="formData.documentNumber" type="text" placeholder="Enter document number" class="form-input" required /> Document Number
<span class="text-red-500">*</span>
</label>
<input
v-model="formData.documentNumber"
type="text"
placeholder="Enter document number"
class="form-input"
/>
</div> </div>
<div class="flex flex-col"> <div class="flex flex-col">
<label class="block text-sm font-medium text-gray-700 mb-2">Subject <span class="text-red-500">*</span></label> <label class="block text-sm font-medium mb-2">
<input v-model="formData.subject" type="text" placeholder="Enter document subject" class="form-input" required /> Subject
<span class="text-red-500">*</span>
</label>
<input
v-model="formData.subject"
type="text"
placeholder="Enter document subject"
class="form-input"
/>
</div> </div>
</div> </div>
<div class="mt-6"> <div class="mt-6">
<label class="block text-sm font-medium text-gray-700 mb-2">Document Body <span class="text-red-500">*</span></label> <label class="block text-sm font-medium mb-2">
<textarea v-model="formData.body" placeholder="Enter document body" class="w-full" rows="5"></textarea> Document Body
<span class="text-red-500">*</span>
</label>
<textarea
v-model="formData.body"
placeholder="Enter document body"
class="w-full border p-2"
rows="5"
></textarea>
</div> </div>
</div> </div>
<div class="mb-8"> <div class="mb-8">
<h2 class="text-lg font-semibold text-gray-700 mb-4">Recipient Information</h2> <h2 class="text-base font-semibold mb-3">Recipient Information</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="flex flex-col"> <div class="flex flex-col">
<label class="block text-sm font-medium text-gray-700 mb-2">Recipient Name</label> <label class="block text-sm font-medium mb-2">Recipient Name</label>
<input v-model="formData.recipientName" type="text" class="form-input" /> <input v-model="formData.recipientName" type="text" class="form-input" />
</div> </div>
<div class="flex flex-col"> <div class="flex flex-col">
<label class="block text-sm font-medium text-gray-700 mb-2">Recipient Contact</label> <label class="block text-sm font-medium mb-2">Recipient Contact</label>
<input v-model="formData.recipientContact" type="tel" class="form-input" /> <input v-model="formData.recipientContact" type="tel" class="form-input" />
</div> </div>
<div class="flex flex-col md:col-span-2"> <div class="flex flex-col md:col-span-2">
<label class="block text-sm font-medium text-gray-700 mb-2">Recipient Address</label> <label class="block text-sm font-medium mb-2">Recipient Address</label>
<input v-model="formData.recipientAddress" type="text" class="form-input" /> <input v-model="formData.recipientAddress" type="text" class="form-input" />
</div> </div>
</div> </div>
@ -78,32 +101,45 @@
<div class="mb-8"> <div class="mb-8">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="flex flex-col"> <div class="flex flex-col">
<label class="block text-sm font-medium text-gray-700 mb-2">Issued Date</label> <label class="block text-sm font-medium mb-2">Issued Date</label>
<input v-model="formData.issuedDate" type="date" class="form-input" /> <input v-model="formData.issuedDate" type="date" class="form-input" />
</div> </div>
<div class="flex flex-col"> <div class="flex flex-col">
<label class="block text-sm font-medium text-gray-700 mb-2">Dispatch Date</label> <label class="block text-sm font-medium mb-2">Dispatch Date</label>
<input v-model="formData.dispatchDate" type="date" class="form-input" /> <input v-model="formData.dispatchDate" type="date" class="form-input" />
</div> </div>
</div> </div>
</div> </div>
<div class="mb-8"> <div class="mb-8">
<h2 class="text-lg font-semibold text-gray-700 mb-4">Attachments</h2> <h2 class="text-base font-semibold mb-3">Attachments</h2>
<div class="border-2 border-dashed p-6 text-center cursor-pointer hover:bg-gray-50" @click="triggerFileInput"> <div class="border-2 border-dashed p-6 text-center cursor-pointer" @click="triggerFileInput">
<input type="file" multiple @change="handleFileUpload" class="hidden" ref="fileInputRef" accept=".pdf,.doc,.docx,.xls,.xlsx,.jpg,.png" /> <input
<p class="text-gray-600 text-sm mb-2">Click to upload or drag and drop</p> type="file"
multiple
@change="handleFileUpload"
class="hidden"
ref="fileInputRef"
accept=".pdf,.doc,.docx,.xls,.xlsx,.jpg,.png"
/>
<p class="text-sm mb-2">Click to upload or drag and drop</p>
<div v-if="formData.attachments.length > 0" class="mt-4 text-left"> <div v-if="formData.attachments.length > 0" class="mt-4 text-left">
<ul class="space-y-2"> <ul class="space-y-2">
<li v-for="(file, index) in formData.attachments" :key="index" class="flex justify-between items-center bg-gray-100 p-2 rounded"> <li
v-for="(file, index) in formData.attachments"
:key="index"
class="flex justify-between items-center border p-2"
>
<span class="text-sm truncate">{{ file.name }}</span> <span class="text-sm truncate">{{ file.name }}</span>
<button type="button" @click.stop="removeFile(index)" class="text-red-500 text-xs">Remove</button> <button type="button" @click.stop="removeFile(index)" class="text-sm">
Remove
</button>
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
</div> </div>
</form> </div>
</div> </div>
</Towser> </Towser>
</template> </template>
@ -118,10 +154,7 @@ const DartaTowserStore = createOverlayStore("darta-towser")();
const { show } = storeToRefs(DartaTowserStore); const { show } = storeToRefs(DartaTowserStore);
const towser = ref({ const towser = ref({
title: [ title: [{ name: "Darta", link: "#" }, { name: "Create" }],
{ name: "Darta", link: "#" },
{ name: "Create" }
],
action: [ action: [
{ {
title: "Close", title: "Close",
@ -132,23 +165,29 @@ const towser = ref({
emit: "onSave", emit: "onSave",
}, },
], ],
}) });
const departments = ref([{ id: 1, name: 'Administration' }, { id: 2, name: 'HR' }]); const departments = ref([
const documentCategories = ref([{ id: 1, name: 'Confidential' }, { id: 2, name: 'Public' }]); { id: 1, name: "Administration" },
{ id: 2, name: "HR" },
]);
const documentCategories = ref([
{ id: 1, name: "Confidential" },
{ id: 2, name: "Public" },
]);
const formData = reactive({ const formData = reactive({
department: null, department: null,
documentCategory: null, documentCategory: null,
documentNumber: '', documentNumber: "",
subject: '', subject: "",
body: '', body: "",
recipientName: '', recipientName: "",
recipientContact: '', recipientContact: "",
recipientAddress: '', recipientAddress: "",
issuedDate: '', issuedDate: "",
dispatchDate: '', dispatchDate: "",
attachments: [] as File[] attachments: [] as File[],
}); });
const fileInputRef = ref<HTMLInputElement | null>(null); const fileInputRef = ref<HTMLInputElement | null>(null);
@ -159,7 +198,7 @@ const onClose = () => {
}; };
const onSave = () => { const onSave = () => {
submitForm(); handleSave();
}; };
const triggerFileInput = () => { const triggerFileInput = () => {
@ -178,13 +217,32 @@ const removeFile = (index: number) => {
}; };
const resetForm = () => { const resetForm = () => {
formData.documentNumber = ''; formData.department = null;
formData.subject = ''; formData.documentCategory = null;
formData.documentNumber = "";
formData.subject = "";
formData.body = "";
formData.recipientName = "";
formData.recipientContact = "";
formData.recipientAddress = "";
formData.issuedDate = "";
formData.dispatchDate = "";
formData.attachments = []; formData.attachments = [];
}; };
const submitForm = async () => { const handleSave = async () => {
console.log("Submitting:", formData); if (
!formData.department ||
!formData.documentCategory ||
!formData.documentNumber ||
!formData.subject ||
!formData.body
) {
console.error("Please fill in all required fields");
return;
}
console.log("Saving:", formData);
onClose(); onClose();
}; };
</script> </script>

View File

@ -19,7 +19,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { ref } from "vue";
import { BStoAD, NepaliDate } from "nepali-date-library";
import { storeToRefs } from "pinia"; import { storeToRefs } from "pinia";
import Create from "@/views/Darta/Create.vue"; import Create from "@/views/Darta/Create.vue";
import { createGenericStore } from "@/stores/GenericStore"; import { createGenericStore } from "@/stores/GenericStore";