import {selectedCouriers, courierMap, fulfillments} from '@src/storages/tracking'; import { AdditionalFields, Fulfillment, FulfillmentFactory, FulfillmentTrackingFactory, } from '@src/typings/trackings'; import {createMemo, For, Show, Switch, Match, Accessor, createSignal} from 'solid-js'; import {capitalize} from 'lodash-es'; import Modal from '../Modal'; import NumberInput from '../NumberInput'; import styles from './EditTrackingModal.module.scss'; import { calcUnfulfilledItems } from '@src/utils/common'; interface Props { visible: boolean; onOk(v: Fulfillment): void; onCancel(): void; orderId: string; } export const [title, setTitle] = createSignal(''); export const [editingFulfillment, setEditingFulfillment] = createSignal(FulfillmentFactory.createDefault()); export default function EditTrackingModal(props: Props) { const MAX_TRACKING_NUMBER = 20; const [trackingIndexCourierMap, setTrackingIndexCourierMap] = createSignal(new Map()); function updateFormValueAtIndex(index: Accessor, field: string, newValue: string) { setEditingFulfillment(f => { const newFulfillments = {...f}; switch (field){ case "tracking_number": newFulfillments.trackings[index()].tracking_number = newValue break; case "slug": newFulfillments.trackings[index()].slug = newValue setTrackingIndexCourierMap(prev => { const m = new Map(Object.assign([], prev)); m.set(index(), newValue); return m; }); break; } return newFulfillments; }); } function updateAdditionalFieldsAtIndex(index: Accessor, field: string, newValue: string) { setEditingFulfillment(f => { const newFulfillments = {...f}; switch (field){ case "account_number": newFulfillments.trackings[index()].additional_fields.account_number = newValue break; case "postal_code": newFulfillments.trackings[index()].additional_fields.postal_code = newValue break; case "key": newFulfillments.trackings[index()].additional_fields.key = newValue break; case "destination_country": newFulfillments.trackings[index()].additional_fields.destination_country = newValue break; case "state": newFulfillments.trackings[index()].additional_fields.state = newValue break; case "ship_date": newFulfillments.trackings[index()].additional_fields.ship_date = newValue break; } return newFulfillments; }); } function addTracking() { setEditingFulfillment(f => { const newFulfillments = {...f}; newFulfillments.trackings.push(FulfillmentTrackingFactory.createDefault()); return newFulfillments; }); } function removeTracking(index: Accessor) { const newTrackings = [...editingFulfillment().trackings]; newTrackings.splice(index(), 1); setEditingFulfillment({ ...editingFulfillment(), trackings: newTrackings }); } function additionalFields(slug: string) { const r = courierMap().get(slug)?.required_fields || []; return r.map((item) => ({ key: item.replace(/^tracking_/, '') as keyof AdditionalFields, name: item .replace(/^tracking_/, '') .split('_') .map(capitalize) .join(' '), })); }; const otherFulfillments = createMemo(() => { if (editingFulfillment()) { return fulfillments().filter((t) => t.id !== editingFulfillment().id); } else { return fulfillments(); } }); const otherFulfillmentsTrackings = createMemo(() => { let filter = new Map(); for (const otherFulfillment of otherFulfillments()) { for (let t of otherFulfillment.trackings) { let exist = filter.get(t.slug + t.tracking_number); if (exist === undefined) { filter.set(t.slug + t.tracking_number, true); } } } return filter }); const remainLineItems = createMemo(() => calcUnfulfilledItems(otherFulfillments())); const validator = createMemo(() => { let isValid = true; let errors: string = ''; const items = editingFulfillment().items; if (!items || items.length === 0) { return {isValid: false, errors: 'Required items'}; } // 任意 item.quantity > 0 即可 isValid = false; items.forEach((item) => { if (item.quantity > 0) { isValid = true; } }); if (!isValid) { return {isValid: false, errors: 'Required items'}; } let filter = new Map(); for (const tracking of editingFulfillment().trackings) { if (tracking.slug === '') { return { isValid: false, errors: 'Required tracking slug' }; } if (tracking.tracking_number === '') { return { isValid: false, errors: 'Required tracking number' }; } if (tracking.tracking_number.length > 256) { return { isValid: false, errors: 'Tracking number invalid' }; } if (tracking.tracking_number.includes(',')) { return { isValid: false, errors: 'Tracking number invalid' }; } // check if tracking number has already been added by other fulfillments let exist = otherFulfillmentsTrackings().get(tracking.slug + tracking.tracking_number); if (exist) { return { isValid: false, errors: 'Tracking number has already been added' }; } // check if tracking number has already been added by current fulfillment exist = filter.get(tracking.slug + tracking.tracking_number); if (exist) { return { isValid: false, errors: 'Tracking number has already been added' }; } if (exist === undefined) { filter.set(tracking.slug + tracking.tracking_number, true); } let requiredFields = courierMap().get(tracking.slug)?.required_fields || []; if (requiredFields.length > 0) { requiredFields.forEach((field) => { let fieldKey = field.replace(/^tracking_/, '') as keyof AdditionalFields; let fieldName = fieldKey.split('_').join(' '); if (tracking.additional_fields[fieldKey] === '') { isValid = false; errors = `Required ${fieldName}`; } if (tracking.additional_fields[fieldKey].length > 256) { isValid = false; errors = `${fieldName} invalid`; } }); } } if (editingFulfillment().trackings.length > MAX_TRACKING_NUMBER || editingFulfillment().trackings.length == 0) { isValid = false; errors = 'Tracking number limit exceeded'; } return { isValid, errors }; }); const handleLineItemChange = (id: number, value: number) => { setEditingFulfillment(f => { const newFulfillment = {...f}; let i = newFulfillment.items?.find((item) => item.id === id); if (i !== undefined) { i.quantity = value } else { newFulfillment.items?.push({id: id, quantity: value}); } return newFulfillment; }); }; const handleOk = () => { props.onOk(editingFulfillment()); }; const getTitle = createMemo( () => { return title().toString() + ` tracking - order - #${props.orderId}` } ); const buttonText = createMemo( () => { if (title().toString() == 'Edit') { return 'Save' } return 'Add' } ); return (
All items have been fulfilled
}> 0}> {(item) => ( )}
Items Qty.
{item.name} i.id === item.id)?.quantity || 0} onChange={(val) => handleLineItemChange(item.id, val || 0)} />

{validator().errors}

{(tracking, index) =>
{(item) => (
)}
}

); }