@traky-app/ui 1.6.4 → 1.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/registry/traky/json/internal-chat-panel.json +1 -1
- package/registry/traky/json/office-address-form.json +5 -1
- package/registry/traky/ui/internal-chat-panel.tsx +1417 -71
- package/registry/traky/ui/office-address-form.tsx +122 -76
- package/src/ui/internal-chat-panel.tsx +1417 -71
- package/src/ui/office-address-form.tsx +80 -43
|
@@ -5,6 +5,8 @@ import { IconEdit, IconMapPin, IconPlus } from "@tabler/icons-react"
|
|
|
5
5
|
import type { Icon } from "@tabler/icons-react"
|
|
6
6
|
|
|
7
7
|
import { cn } from "@/lib/utils"
|
|
8
|
+
import { fetchStates } from "@/lib/geo-locations"
|
|
9
|
+
import { googleMapsSelectionToFormPatch } from "@/lib/google-maps-address"
|
|
8
10
|
import {
|
|
9
11
|
AlertDialog,
|
|
10
12
|
AlertDialogAction,
|
|
@@ -14,7 +16,7 @@ import {
|
|
|
14
16
|
} from "@/components/ui/alert-dialog"
|
|
15
17
|
import { Button } from "@/components/ui/button"
|
|
16
18
|
import { Spinner } from "@/components/ui/spinner"
|
|
17
|
-
import {
|
|
19
|
+
import { StateSelect } from "@/components/ui/state-select"
|
|
18
20
|
import {
|
|
19
21
|
Card,
|
|
20
22
|
CardContent,
|
|
@@ -24,6 +26,8 @@ import {
|
|
|
24
26
|
CardTitle,
|
|
25
27
|
} from "@/components/ui/card"
|
|
26
28
|
import { EntityIcon } from "@/components/ui/entity-icon"
|
|
29
|
+
import { CitySelect } from "@/components/ui/city-select"
|
|
30
|
+
import { CountrySelect } from "@/components/ui/country-select"
|
|
27
31
|
import { GoogleMapsAddressPicker } from "@/components/ui/google-maps-address-picker"
|
|
28
32
|
import { Input } from "@/components/ui/input"
|
|
29
33
|
import { Label } from "@/components/ui/label"
|
|
@@ -81,17 +85,6 @@ function OfficeAddressEntryModeSwitch({
|
|
|
81
85
|
/** `customer` = dirección de envío (contacto/portal). `enterprise` = sucursal o bodega. */
|
|
82
86
|
export type OfficeAddressFormVariant = "customer" | "enterprise"
|
|
83
87
|
|
|
84
|
-
const OFFICE_ADDRESS_COUNTRY_OPTIONS: { code: string; label: string }[] = [
|
|
85
|
-
{ code: "EC", label: "Ecuador" },
|
|
86
|
-
{ code: "US", label: "Estados Unidos" },
|
|
87
|
-
{ code: "MX", label: "México" },
|
|
88
|
-
{ code: "CO", label: "Colombia" },
|
|
89
|
-
{ code: "PE", label: "Perú" },
|
|
90
|
-
{ code: "CL", label: "Chile" },
|
|
91
|
-
{ code: "PA", label: "Panamá" },
|
|
92
|
-
{ code: "CR", label: "Costa Rica" },
|
|
93
|
-
]
|
|
94
|
-
|
|
95
88
|
const FAX_COUNTRY_CODES = new Set(["US", "CA", "PR"])
|
|
96
89
|
|
|
97
90
|
export function isOfficeAddressFaxCountry(countryCode: string | undefined) {
|
|
@@ -232,6 +225,7 @@ export type OfficeAddressFormCardProps = {
|
|
|
232
225
|
countryField?: React.ReactNode
|
|
233
226
|
phoneField?: React.ReactNode
|
|
234
227
|
faxField?: React.ReactNode
|
|
228
|
+
manualFields?: React.ReactNode
|
|
235
229
|
}
|
|
236
230
|
|
|
237
231
|
export function OfficeAddressFormCard({
|
|
@@ -254,6 +248,7 @@ export function OfficeAddressFormCard({
|
|
|
254
248
|
countryField,
|
|
255
249
|
phoneField,
|
|
256
250
|
faxField,
|
|
251
|
+
manualFields,
|
|
257
252
|
}: OfficeAddressFormCardProps) {
|
|
258
253
|
const busy = disabled
|
|
259
254
|
const isCustomer = variant === "customer"
|
|
@@ -274,29 +269,51 @@ export function OfficeAddressFormCard({
|
|
|
274
269
|
}
|
|
275
270
|
|
|
276
271
|
const embedded = layout === "dialog"
|
|
272
|
+
const countryCode = form.countryCode?.trim().toUpperCase() ?? ""
|
|
273
|
+
const [stateCode, setStateCode] = React.useState("")
|
|
274
|
+
|
|
275
|
+
React.useEffect(() => {
|
|
276
|
+
const stateName = form.stateOrProvince?.trim() ?? ""
|
|
277
|
+
if (!countryCode || !stateName) {
|
|
278
|
+
setStateCode("")
|
|
279
|
+
return
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
let cancelled = false
|
|
283
|
+
void fetchStates(countryCode).then((list) => {
|
|
284
|
+
if (cancelled) return
|
|
285
|
+
const wanted = stateName.toLowerCase()
|
|
286
|
+
const match = list.find(
|
|
287
|
+
(item) =>
|
|
288
|
+
item.name.toLowerCase() === wanted ||
|
|
289
|
+
item.code.toLowerCase() === wanted,
|
|
290
|
+
)
|
|
291
|
+
setStateCode(match?.code ?? "")
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
return () => {
|
|
295
|
+
cancelled = true
|
|
296
|
+
}
|
|
297
|
+
}, [countryCode, form.stateOrProvince])
|
|
277
298
|
|
|
278
299
|
const countryControl =
|
|
279
300
|
countryField ?? (
|
|
280
|
-
<
|
|
281
|
-
|
|
301
|
+
<CountrySelect
|
|
302
|
+
className="w-full"
|
|
303
|
+
size="lg"
|
|
304
|
+
value={form.countryCode}
|
|
282
305
|
disabled={busy}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
{c.label}
|
|
295
|
-
</SelectItem>
|
|
296
|
-
))}
|
|
297
|
-
</SelectGroup>
|
|
298
|
-
</SelectContent>
|
|
299
|
-
</Select>
|
|
306
|
+
searchPlaceholder="Escribe el país…"
|
|
307
|
+
onChange={(country) => {
|
|
308
|
+
setStateCode("")
|
|
309
|
+
onFormChange((prev) => ({
|
|
310
|
+
...prev,
|
|
311
|
+
countryCode: country.code,
|
|
312
|
+
stateOrProvince: "",
|
|
313
|
+
city: "",
|
|
314
|
+
}))
|
|
315
|
+
}}
|
|
316
|
+
/>
|
|
300
317
|
)
|
|
301
318
|
|
|
302
319
|
return (
|
|
@@ -385,51 +402,75 @@ export function OfficeAddressFormCard({
|
|
|
385
402
|
{countryControl}
|
|
386
403
|
</div>
|
|
387
404
|
|
|
388
|
-
{addressEntryMode === "manual"
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
405
|
+
{addressEntryMode === "manual"
|
|
406
|
+
? (manualFields ?? (
|
|
407
|
+
<>
|
|
408
|
+
<div className="col-span-1 space-y-1 sm:col-span-2">
|
|
409
|
+
<Label htmlFor="office-address">Dirección</Label>
|
|
410
|
+
<Input
|
|
411
|
+
id="office-address"
|
|
412
|
+
name="address"
|
|
413
|
+
value={form.address}
|
|
414
|
+
onChange={handleChange}
|
|
415
|
+
placeholder="Calle y número"
|
|
416
|
+
disabled={busy}
|
|
417
|
+
/>
|
|
418
|
+
</div>
|
|
419
|
+
<div className="space-y-1">
|
|
420
|
+
<Label htmlFor="office-state">
|
|
421
|
+
Estado / Región / Municipio
|
|
422
|
+
</Label>
|
|
423
|
+
<StateSelect
|
|
424
|
+
id="office-state"
|
|
425
|
+
className="w-full"
|
|
426
|
+
countryCode={countryCode}
|
|
427
|
+
value={form.stateOrProvince}
|
|
428
|
+
disabled={busy}
|
|
429
|
+
onChange={(option) => {
|
|
430
|
+
setStateCode(option?.code ?? "")
|
|
431
|
+
onFormChange((prev) => ({
|
|
432
|
+
...prev,
|
|
433
|
+
stateOrProvince: option?.name ?? "",
|
|
434
|
+
city: "",
|
|
435
|
+
}))
|
|
436
|
+
}}
|
|
437
|
+
/>
|
|
438
|
+
</div>
|
|
439
|
+
<div className="space-y-1">
|
|
440
|
+
<Label htmlFor="office-city">
|
|
441
|
+
Ciudad / Pueblo / Distrito
|
|
442
|
+
</Label>
|
|
443
|
+
<CitySelect
|
|
444
|
+
id="office-city"
|
|
445
|
+
className="w-full"
|
|
446
|
+
countryCode={countryCode}
|
|
447
|
+
stateCode={stateCode}
|
|
448
|
+
value={form.city}
|
|
449
|
+
disabled={busy}
|
|
450
|
+
onChange={(option) => {
|
|
451
|
+
onFormChange((prev) => ({
|
|
452
|
+
...prev,
|
|
453
|
+
city: option?.name ?? "",
|
|
454
|
+
...(option?.stateName
|
|
455
|
+
? { stateOrProvince: option.stateName }
|
|
456
|
+
: {}),
|
|
457
|
+
}))
|
|
458
|
+
}}
|
|
459
|
+
/>
|
|
460
|
+
</div>
|
|
461
|
+
<div className="space-y-1">
|
|
462
|
+
<Label htmlFor="office-postal">Código postal</Label>
|
|
463
|
+
<Input
|
|
464
|
+
id="office-postal"
|
|
465
|
+
name="postalCode"
|
|
466
|
+
value={form.postalCode}
|
|
467
|
+
onChange={handleChange}
|
|
468
|
+
disabled={busy}
|
|
469
|
+
/>
|
|
470
|
+
</div>
|
|
471
|
+
</>
|
|
472
|
+
))
|
|
473
|
+
: null}
|
|
433
474
|
|
|
434
475
|
{addressEntryMode === "gps" && form.address.trim() ? (
|
|
435
476
|
<div className="col-span-1 rounded-lg border border-border bg-muted/30 px-3 py-2.5 text-sm sm:col-span-2">
|
|
@@ -607,6 +648,7 @@ type OfficeAddressFormSharedProps = {
|
|
|
607
648
|
countryField?: React.ReactNode
|
|
608
649
|
phoneField?: React.ReactNode
|
|
609
650
|
faxField?: React.ReactNode
|
|
651
|
+
manualFields?: React.ReactNode
|
|
610
652
|
}
|
|
611
653
|
|
|
612
654
|
type OfficeAddressFormInlineProps = OfficeAddressFormSharedProps & {
|
|
@@ -673,6 +715,7 @@ function OfficeAddressFormInline({
|
|
|
673
715
|
countryField,
|
|
674
716
|
phoneField,
|
|
675
717
|
faxField,
|
|
718
|
+
manualFields,
|
|
676
719
|
}: OfficeAddressFormInlineProps) {
|
|
677
720
|
const internal = useOfficeAddressForm({ initialValues, initialEntryMode })
|
|
678
721
|
const form = controlledForm ?? internal.form
|
|
@@ -702,6 +745,7 @@ function OfficeAddressFormInline({
|
|
|
702
745
|
countryField={countryField}
|
|
703
746
|
phoneField={phoneField}
|
|
704
747
|
faxField={faxField}
|
|
748
|
+
manualFields={manualFields}
|
|
705
749
|
/>
|
|
706
750
|
)
|
|
707
751
|
}
|
|
@@ -728,6 +772,7 @@ function OfficeAddressFormModal({
|
|
|
728
772
|
countryField,
|
|
729
773
|
phoneField,
|
|
730
774
|
faxField,
|
|
775
|
+
manualFields,
|
|
731
776
|
icon,
|
|
732
777
|
form: controlledForm,
|
|
733
778
|
onFormChange: controlledOnFormChange,
|
|
@@ -816,6 +861,7 @@ function OfficeAddressFormModal({
|
|
|
816
861
|
countryField={countryField}
|
|
817
862
|
phoneField={phoneField}
|
|
818
863
|
faxField={faxField}
|
|
864
|
+
manualFields={manualFields}
|
|
819
865
|
form={form}
|
|
820
866
|
onFormChange={setForm}
|
|
821
867
|
addressEntryMode={addressEntryMode}
|