diff --git a/addons/laundry_management/static/src/js/quick_create_partner.js b/addons/laundry_management/static/src/js/quick_create_partner.js new file mode 100644 index 0000000..49c20c3 --- /dev/null +++ b/addons/laundry_management/static/src/js/quick_create_partner.js @@ -0,0 +1,72 @@ +/** @odoo-module + * + * LaundryQuickCreatePartner — POS-only quick create. + * + * UX rules: + * - Phone is REQUIRED and the FIRST input (autofocused on mount). + * - Name is OPTIONAL. If empty on confirm, the backend + * `res.partner.laundry_quick_create` falls back to using the phone + * value as the partner name (single source of truth — JS does not + * duplicate that fallback). + * - Street is fully optional. + * + * All user-facing strings come from `_t()` getters so the active + * language switches the popup text cleanly. No mixed-language labels. + */ +import { Component, useState, useRef, onMounted } from "@odoo/owl"; +import { Dialog } from "@web/core/dialog/dialog"; +import { _t } from "@web/core/l10n/translation"; + +export class LaundryQuickCreatePartner extends Component { + static components = { Dialog }; + static template = "laundry_management.QuickCreatePartner"; + static props = { + getPayload: { type: Function }, + close: { type: Function }, + }; + + setup() { + this.state = useState({ + phone: "", + name: "", + street: "", + phoneError: false, + }); + this.phoneRef = useRef("phoneInput"); + onMounted(() => { + if (this.phoneRef.el) this.phoneRef.el.focus(); + }); + } + + // ── Translatable labels (computed each render so language change + // propagates without a remount) ───────────────────────────────── + get title() { return _t("Quick Create Customer"); } + get labelPhone() { return _t("Phone / Mobile"); } + get labelName() { return _t("Name"); } + get labelStreet() { return _t("Street"); } + get labelCreate() { return _t("Create"); } + get labelCancel() { return _t("Cancel"); } + get nameOptionalHint() { return _t("(optional — phone is used if empty)"); } + get placeholderPhone() { return _t("e.g. +966 50 123 4567"); } + get placeholderName() { return _t("Customer name"); } + get placeholderStreet() { return _t("Building, street, district…"); } + get errorPhoneRequired() { return _t("Phone is required."); } + + confirm() { + const phone = (this.state.phone || "").trim(); + if (!phone) { + this.state.phoneError = true; + return; + } + this.props.getPayload({ + phone, + name: (this.state.name || "").trim(), // empty → backend falls back to phone + street: (this.state.street || "").trim(), + }); + this.props.close(); + } + + cancel() { + this.props.close(); + } +}