import { toTypedSchema } from "@vee-validate/zod"; import { storeToRefs } from "pinia"; import { useForm } from "vee-validate"; import { computed, ref, watch } from "vue"; import { useRoute, useRouter } from "vue-router"; import { fullCurrentDate } from "src/constants"; import { invertDate } from "src/functions/invertDate"; import { quasarNotify } from "src/functions/quasarNotify"; import { useCartStore } from "src/stores/cart"; import { useFormStore } from "src/stores/forms"; import { useModalStore } from "src/stores/modalStore"; import { useRangePriceStore } from "src/stores/rangePrice"; import { availabilitySchema } from "src/utils/zod/schemas"; import { rangePriceSchema } from "src/utils/zod/schemas/rangePriceSchema"; import { useLocalStorage } from "./useLocalStorage"; /** * Custom hook for managing postal calendar functionality. * * @param {Object} options - The options for the hook. * @param {string} options.modalItem - The modal item. * @param {string} options.type - The type of the calendar. * @returns {Object} - The hook functions and properties. */ export function usePostalCalendar({ modalItem = "", type = "home" }) { const route = useRoute(); const { push } = useRouter(); const { addItem, getItemSession, removeItem } = useLocalStorage(); const modalStore = useModalStore(); const rangePriceStore = useRangePriceStore(); const { rangeValue } = storeToRefs(rangePriceStore); const formStore = useFormStore(); const { sortProductFilters, availability: availabilityForm } = storeToRefs(formStore); const cartStore = useCartStore(); const { addToCart, getProducts } = cartStore; const { products, cart } = storeToRefs(cartStore); const min = 0; const max = 200; const category = ref(route.path.split("/")[2]); const categoryObj = { plantas: "Floranet Plantas", ramos: "Floranet Ramos", }; const availability = ref(getItemSession("availability")); const availabilityFormKeys = computed(() => { return Object.fromEntries( Object.entries(availabilityForm.value).filter( ([key, value]) => value !== "" ) ); }); const isAvailabilityEmpty = computed(() => { return ( Object.keys(availability.value || availabilityFormKeys.value).length === 0 ); }); const isPostalCalendarEmpty = computed(() => { if (category.value === "ramos" || category.value === "plantas") { const isAvailabilityEmptyForm = Object.keys(availabilityFormKeys.value).length === 0; return isAvailabilityEmptyForm; } return isAvailabilityEmpty.value; }); let DATE_INITIAL const [YEAR, MONTH, DAY] = fullCurrentDate.replaceAll("/", "-").split("-"); const CURRENT_DATE = `${DAY}-${MONTH}-${YEAR}`; DATE_INITIAL = CURRENT_DATE if (availability.value.dateExpired) { const [yearStorage, monthStorage, dayStorage] = availability.value.dateExpired.replaceAll("/", "-").split("-"); const STORAGE_DATE = `${dayStorage}-${monthStorage}-${yearStorage}`; DATE_INITIAL = STORAGE_DATE } const POSTAL_CODE_INITIAL = availability.value.postalCode ? availability.value.postalCode : "" const { handleSubmit, handleReset, defineField, errors, setValues, setFieldError, } = useForm({ validateOnMount: false, validationSchema: toTypedSchema( type !== "filter" ? availabilitySchema : rangePriceSchema ), initialValues: { range: { min, max, }, postalCode: POSTAL_CODE_INITIAL, date: DATE_INITIAL, }, initialTouched: { date: availability.value.dateExpired ? true : false, postalCode: true, }, }); const options = { validateOnBlur: false, validateOnChange: false, validateOnInput: false, validateOnModelUpdate: false, }; const [calendar, calendarAttrs] = defineField("date", options); const [postalCode, postalCodeAttrs] = defineField("postalCode", options); const [priceRange, priceRangeAttrs] = defineField("range", options); const [dedication, dedicationAttrs] = defineField("dedication"); watch(errors, (newErrors) => { const hasErrors = { range: newErrors.range, dedication: newErrors.dedication, }; for (const [field, hasError] of Object.entries(hasErrors)) { if (hasError) { quasarNotify({ message: newErrors[field], type: "erro" }); } } }); watch([() => route.path, () => sortProductFilters.value], ([newPath]) => { const categoryPath = newPath.split("/")[2]; category.value = categoryPath; availabilityForm.value.dateExpired = ""; availability.value.postalCode = ""; sortProductFilters.value.isOpenOrderFilter = false; sortProductFilters.value.order = undefined; }); const removeCart = () => { removeItem("cart"); cart.value = []; }; const onSuccess = async (values) => { const handleAvailability = async () => { addItem("availability", { postalCode: values.postalCode, dateExpired: invertDate(values.date), }); removeCart(); availabilityForm.value.dateExpired = invertDate(values.date); availabilityForm.value.postalCode = values.postalCode; await getProducts({ type: categoryObj[category.value], postalCode: values.postalCode, dateExpired: invertDate(values.date), }); }; const handleHome = async () => { addItem("availability", { postalCode: values.postalCode, dateExpired: invertDate(values.date), }); availabilityForm.value.dateExpired = invertDate(values.date); availabilityForm.value.postalCode = values.postalCode; removeCart(); const callback = async () => { await push("/categoria/all"); }; await getProducts( { postalCode: values.postalCode, dateExpired: invertDate(values.date), }, callback ); }; const handleProduct = async () => { addItem("availability", { postalCode: values.postalCode, dateExpired: invertDate(values.date), }); removeCart(); availabilityForm.value.dateExpired = invertDate(values.date); availabilityForm.value.postalCode = values.postalCode; await getProducts({ postalCode: values.postalCode, dateExpired: invertDate(values.date), }); const hasProduct = computed(() => { return products.value.data.some((item) => { const date = new Date(item.dateExpired); const day = date.getDate(); const month = (date.getMonth() + 1).toString().padStart(2, "0"); const year = date.getFullYear(); const dateExpired = `${day}/${month}/${year}`; const dateSelected = values.date.replaceAll("-", "/"); const id = +route.path.split("/")[2]; return ( item.postalCode === values.postalCode && item.id === id && dateSelected <= dateExpired ); }); }); if (!hasProduct.value) { quasarNotify({ message: "Código postal y fecha de caducidad añadidos con éxito", type: "success", }); return; } // go(); addToCart(products.value.current, dedication); }; const handleFilter = async () => { rangeValue.value.max = values.range.max; rangeValue.value.min = values.range.min; const params = { type: categoryObj[category.value], minPrice: values.range.min, maxPrice: values.range.max, postalCode: availabilityForm.value.postalCode, dateExpired: availabilityForm.value.dateExpired, }; if (category.value === "all") { params.postalCode = availability.value.postalCode || availabilityForm.value.postalCode; params.dateExpired = availability.value.dateExpired || availabilityForm.value.dateExpired; const { type, ...rest } = params; await getProducts({ ...rest }); return; } getProducts(params); }; const handleDefault = () => { console.error( `INVALID TYPE! TYPE: ${type}, ONLY HOME, PRODUCT AND FILTER ARE VALID!` ); }; const handlers = { availability: handleAvailability, home: handleHome, product: handleProduct, filter: handleFilter, default: handleDefault, }; const handler = handlers[type] || handlers.default; await handler(); if (modalItem) { modalStore[modalItem] = false; } handleReset(); }; const onError = ({ values, errors, results }) => { const hasErrors = { postalCode: !!errors.postalCode, date: !!errors.date, }; for (const [field, hasError] of Object.entries(hasErrors)) { if (hasError) { quasarNotify({ message: errors[field], type: "erro" }); } } }; const onSubmit = handleSubmit(onSuccess, onError); return { onSubmit, setValues, handleReset, modalStore, setFieldError, isAvailabilityEmpty, isPostalCalendarEmpty, availabilityFormKeys, category, fields: { calendar, calendarAttrs, postalCode, postalCodeAttrs, priceRange, priceRangeAttrs, dedication, dedicationAttrs, }, errors, }; }