im new to nuxt and i am currently developing a module and I'm having a hard time implementing imet on a component props. That it should carry into the payload for adding something.
the logic is on the request.vue where i used the props, where there is userselector and user_id, where if userselector is true, user_id will be null and the selected user is automatically selected, but if userselector is false, it will have a dropdown of the users list to be selected and then it should be carried to the payload, for now this is my code but when i select on the user list and click on submit im getting error because the one i selected is not on the payload.
this is my pinia store, approvals.ts
import { defineStore } from "pinia"
const { token } = useAuth()
const config = useRuntimeConfig()
export const APPROVAL_MANPOWERREQ = "Manpower Request"
export interface Approver {
type: string,
user_id: number | null,
userselector: boolean
}
export interface Approval {
id: string | null,
form: string,
approvals: Array<Approver>,
}
export const useApprovalStore = defineStore("approvals", {
state: () => ({
isEdit: false,
formApproval: {} as Approval,
list: [],
pagination: {},
getParams: {},
errorMessage: "",
successMessage: "",
}),
actions: {
async getApproval () {
const { data, error } = await useFetch(
"/api/approvals",
{
baseURL: config.public.HRMS_API_URL,
method: "GET",
headers: {
Authorization: token.value + "",
Accept: "application/json"
},
params: this.getParams,
onResponse: ({ response }) => {
this.list = response._data.data.data.map((val: any) => {
return {
id: val.id,
form: val.form,
approvals: JSON.parse(val.approvals),
}
})
this.pagination = {
first_page: response._data.data.first_page_url,
pages: response._data.data.links,
last_page: response._data.data.last_page_url,
}
},
}
)
if (data) {
return data
} else if (error) {
return error
}
},
async getApprovalByName (approvalName: String) {
const { data } = await useFetch(
"/api/get-form-requests/" + approvalName,
{
baseURL: config.public.HRMS_API_URL,
method: "GET",
headers: {
Authorization: token.value + "",
Accept: "application/json"
},
watch: false,
onResponse: ({ response }) => {
if (response.status !== 200) {
this.errorMessage = response._data.message
} else {
return response._data.data
}
},
}
)
return data.value.data.approvals
},
async createApproval () {
this.successMessage = ""
this.errorMessage = ""
await useFetch(
"/api/approvals",
{
baseURL: config.public.HRMS_API_URL,
method: "POST",
headers: {
Authorization: token.value + "",
Accept: "application/json"
},
body: this.formApproval,
watch: false,
onResponse: ({ response }) => {
if (response.status !== 200) {
this.errorMessage = response._data.message
} else {
this.getApproval()
this.reset()
this.successMessage = response._data.message
}
},
}
)
},
clearMessages () {
this.errorMessage = ""
this.successMessage = ""
},
async editApprovals () {
this.successMessage = ""
this.errorMessage = ""
const { data, error } = await useFetch(
"/api/approvals/" + this.formApproval.id,
{
baseURL: config.public.HRMS_API_URL,
method: "PATCH",
headers: {
Authorization: token.value + "",
Accept: "application/json"
},
body: this.formApproval,
watch: false,
onResponse: ({ response }) => {
if (response.status !== 200) {
this.errorMessage = response._data.message
} else {
this.getApproval()
this.reset()
this.successMessage = response._data.message
}
},
}
)
if (data.value) {
this.getApproval()
this.reset()
this.successMessage = data.value.message
return data
} else if (error.value) {
this.errorMessage = error.value.message
return error
}
},
async deleteApproval (id: number) {
await useFetch(
"/api/approvals/" + id,
{
baseURL: config.public.HRMS_API_URL,
method: "DELETE",
headers: {
Authorization: token.value + "",
Accept: "application/json"
},
watch: false,
onResponse: ({ response }) => {
this.successMessage = response._data.message
this.getApproval()
},
onResponseError: ({ response }) => {
this.errorMessage = response._data.message
},
}
)
},
reset () {
this.approval = {
id: null,
form: null,
approvals: [],
}
this.approvals = []
this.isEdit = false
this.successMessage = ""
this.errorMessage = ""
},
},
})
this is my List.vue component which has the props from the pinia store
<script setup>
import { useUserStore } from "@/stores/hrms/users"
const user = useUserStore()
const { employeeUserList } = storeToRefs(user)
const props = defineProps({
approval: {
type: Object,
required: true,
},
})
const emit = defineEmits(["changeuserId"])
const changeuserId = (event) => {
emit("changeuserId", props.approval, event.target.value)
}
</script>
<template>
<div class="grid grid-cols-2 border border-slate-400 p-2">
<div class="flex flex-col">
<label class="block text-sm font-medium text-gray-900 dark:text-white">Approval Type</label>
<div class="font-semibold text-black">
{{ approval.type }}
</div>
</div>
<div class="flex flex-col">
<label class="block text-sm font-medium text-gray-900 dark:text-white">Approver</label>
<div v-if="approval.userselector">
<select class="w-full" @change="changeuserId">
<option disabled selected>
--Select--
</option>
<option v-for="userSelect in employeeUserList" :key="userSelect.id" :value="userSelect.id">
{{ userSelect.name }}
</option>
</select>
</div>
<div v-else>
<span class="font-semibold">{{ approval.name }}</span>
</div>
</div>
</div>
</template>
and this is the request.vue(where all the inputs)
<script setup>
import { storeToRefs } from "pinia"
import { useManpowerStore, EMPLOYMENT_TYPE, NATURE_REQUESTS, STATUS, GENDER } from "@/stores/employee/manpower"
import { useDepartmentStore } from "@/stores/departments"
import { useApprovalStore, APPROVAL_MANPOWERREQ } from "@/stores/approvals"
const { data: userData } = useAuth()
const departments = useDepartmentStore()
const { departmentsList } = storeToRefs(departments)
const manpowers = useManpowerStore()
const { manpower, errorMessage, successMessage } = storeToRefs(manpowers)
const approvals = useApprovalStore()
const snackbar = useSnackbar()
const boardLoading = ref(false)
manpower.value.requested_by = userData.value.id
manpower.value.approvals = await approvals.getApprovalByName(APPROVAL_MANPOWERREQ)
const handleFileUpload = (event) => {
const file = event.target.files[0]
manpower.value.job_description_attachment = file
}
const addManpwr = async () => {
try {
boardLoading.value = true
await manpowers.createManpower()
if (manpowers.errorMessage !== "") {
snackbar.add({
type: "error",
text: manpowers.errorMessage
})
} else {
snackbar.add({
type: "success",
text: manpowers.successMessage
})
}
} catch {
snackbar.add({
type: "error",
text: manpowers.errorMessage
})
} finally {
manpowers.clearMessages()
boardLoading.value = false
}
}
const changeuserId = (approver, userId) => {
if (approver.userselector === true) {
approver.user_id = null
} else {
approver.user_id = userId
}
console.log("approver:", approver)
console.log("userId:", userId)
}
</script>
<template>
<LayoutBoards title="Manpower Request" :loading="boardLoading" class="w-90">
<div class="text-gray-500 p-2">
<form @submit.prevent="addManpwr">
<!-- {{ manpower }} -->
<div class="grid grid-cols-2 gap-2 sm:grid-cols-2">
<div class="pb-4">
<label for="reqDepartment" class="block text-sm font-medium text-gray-900 dark:text-white">Requesting Department</label>
<select id="reqDepartment" v-model="manpower.requesting_department" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required>
<option value="" disabled selected>
Choose Department
</option>
<option v-for="dpt, index in departmentsList" :key="index" :value=" dpt.id">
{{ dpt.department_name }}
</option>
</select>
</div>
<div>
<div class="grid grid-cols-1 gap-2 sm:grid-cols-2">
<div class="div">
<label for="date_requested" class="block text-sm font-medium text-gray-900 dark:text-white">Date Requested</label>
<input id="date_requested" v-model="manpower.date_requested" type="date" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required>
</div>
<div class="div">
<label for="date_required" class="block text-sm font-medium text-gray-900 dark:text-white">Date Required</label>
<input id="date_required" v-model="manpower.date_required" type="date" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required>
</div>
</div>
</div>
</div>
<div class=" grid grid-cols-1 gap-2 sm:grid-cols-2">
<div class="pb-4">
<label for="position_title" class="block text-sm font-medium text-gray-900 dark:text-white">Position/Title</label>
<input id="position_title" v-model="manpower.position" type="text" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required>
</div>
<div>
<label for="employment_type" class="block text-sm font-medium text-gray-900 dark:text-white">Employment Type</label>
<select id="employment_type" v-model="manpower.employment_type" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required>
<option value="" disabled selected>
Choose Employment Type
</option>
<option v-for="employmentType, index2 in EMPLOYMENT_TYPE" :key="index2" :value="employmentType">
{{ employmentType }}
</option>
</select>
</div>
</div>
<div class=" grid grid-cols-1 gap-2 sm:grid-cols-2">
<div class="pb-4">
<label for="brief_description" class="block text-sm font-medium text-gray-900 dark:text-white">Brief Description</label>
<textarea id="brief_description" v-model="manpower.brief_description" rows="4" class="block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="" />
</div>
<div class="pb-4">
<label for="job_description_attachment" class="block text-sm font-medium text-gray-900 dark:text-white">Job Description Attachment</label>
<input
id="job_description_attachment"
class="block w-full mb-1 text-xs text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-none dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400"
aria-describedby="file_input_help"
type="file"
accept=".doc,.docx,.pdf"
required
@change="handleFileUpload"
>
<p class="flex justify-center mx-auto text-xs text-gray-500 dark:text-gray-300 uppercase">
doc/docx/pdf
</p>
</div>
</div>
<div class="pb-4 grid grid-cols-1 gap-2 sm:grid-cols-5">
<div class="col-span-2">
<label class="block text-sm font-medium text-gray-900 dark:text-white">Nature of Request</label>
<select id="natureReqs" v-model="manpower.nature_of_request" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required>
<option value="" disabled selected>
Choose Nature of Request
</option>
<option v-for="natureReqs, request in NATURE_REQUESTS" :key="request" :value="natureReqs">
{{ natureReqs }}
</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-900 dark:text-white">Age Range</label>
<input id="age_range" v-model="manpower.age_range" type="text" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required>
</div>
<div>
<label class="block text-sm font-medium text-gray-900 dark:text-white">Status</label>
<select id="status" v-model="manpower.status" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required>
<option value="" disabled selected>
Choose Status
</option>
<option v-for="statusType, index3 in STATUS" :key="index3" :value="statusType">
{{ statusType }}
</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-900 dark:text-white">Gender</label>
<select id="gender" v-model="manpower.gender" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required>
<option value="" disabled selected>
Choose Gender
</option>
<option v-for="genderType, gender in GENDER" :key="gender" :value="genderType">
{{ genderType }}
</option>
</select>
</div>
</div>
<div class="pb-4 grid grid-cols-1 gap-2 sm:grid-cols-3">
<div>
<label for="educational_req" class="block text-sm font-medium text-gray-900 dark:text-white">Educational Requirement</label>
<textarea id="educational_req" v-model="manpower.educational_requirement" rows="4" class="block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="" />
</div>
<div class="col-span-2">
<label for="pref_qualification" class="block whitespace-normal text-sm font-medium text-gray-900 dark:text-white">Preferred Qualifications / Experience (not mentioned above or in the Job Description)</label>
<textarea id="pref_qualification" v-model="manpower.preferred_qualifications" rows="4" class="block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="" />
</div>
</div>
<div class="pb-4">
<label for="remarks" class="block text-sm font-medium text-gray-900 dark:text-white">Additional Remarks (Reason for Request)</label>
<textarea id="remarks" v-model="manpower.remarks" rows="4" class="block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="" />
</div>
<div class="pb-4 grid grid-cols-1 gap-2 sm:grid-cols-2">
<div>
<label for="requested_by" class="block text-sm font-medium text-gray-900 dark:text-white">Requested by</label>
<input
id="requested_by"
:value="userData.name"
type="text"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
disabled
>
</div>
</div>
<label for="approved_by" class="block text-sm font-medium text-gray-900 dark:text-white">Approvals</label>
<div>
<HrmsSetupApprovalsList
v-for="(approv, apr) in manpower.approvals"
:key="apr"
:approval="approv"
@changeuser-id="changeuserId"
/>
</div>
<div class="pt-4">
<button type="submit" class=" text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
Submit
</button>
</div>
</form>
<p hidden class="error-message text-red-600 text-center font-semibold mt-2 italic" :class="{ 'fade-out': !errorMessage }">
{{ errorMessage }}
</p>
<p
v-show="successMessage"
hidden
class="success-message text-green-600 text-center font-semibold italic transition-opacity delay-1000"
>
{{ successMessage }}
</p>
</div>
</LayoutBoards>
</template>