import React, { FC, useState } from 'react' import { Button, FormToggle, Modal, TextControl, __experimentalItem as Item, __experimentalItemGroup as ItemGroup, __experimentalInputControlSuffixWrapper as InputControlSuffixWrapper, __experimentalNumberControl as NumberControl, } from '@wordpress/components' import { Notice, Stack } from '@wordpress/ui' import { useAnnounce } from './components/useAnnounce' import { calendar, mapMarker, pencil, published, undo } from '@wordpress/icons' import { useI18n } from '@wordpress/react-i18n' import apiFetch from '@wordpress/api-fetch' import { speak } from '@wordpress/a11y' import SettingsRow from './components/SettingsRow' type ReturnAddress = { name: string addressLine: string addressLine2: string postalCode: string city: string } type ReturnsSettings = { enabled: boolean autoApprove: boolean windowDays: number returnAddress?: ReturnAddress | null otherReturnsPlugin?: boolean } const emptyAddress: ReturnAddress = { name: '', addressLine: '', addressLine2: '', postalCode: '', city: '', } const defaults: ReturnsSettings = { enabled: false, autoApprove: true, windowDays: 30, } const ToggleReturns: FC = () => { const [settings, setSettings] = useState( // @ts-expect-error 2339 window.shopDetails?.returns || defaults ) const [open, setOpen] = useState(false) const [windowDays, setWindowDays] = useState( String(settings.windowDays) ) const [address, setAddress] = useState( settings.returnAddress || emptyAddress ) const [editingAddress, setEditingAddress] = useState(false) const [isSaving, setIsSaving] = useState(false) const [error, setError] = useState() const { __ } = useI18n() const otherReturnsPluginWarning = __( 'WooCommerce Returns and Warranty Requests is active. Use only one of them, so customers see one way to return items.', 'posten-bring-checkout' ) const save = async (changes: Partial): Promise => { setIsSaving(true) setError(undefined) try { const saved: ReturnsSettings = await apiFetch({ path: '/posten-bring-checkout/returns', method: 'POST', data: changes, }) setSettings(saved) // @ts-expect-error 2339 if (window.shopDetails) { // @ts-expect-error 2339 window.shopDetails.returns = saved } setWindowDays(String(saved.windowDays)) if ('returnAddress' in changes) { setAddress(saved.returnAddress || emptyAddress) setEditingAddress(false) } return true } catch (e) { setError( __( 'An error occurred while updating the return settings. Please try again.', 'posten-bring-checkout' ) ) return false } finally { setIsSaving(false) } } const saveWindowDays = async () => { const days = parseInt(windowDays, 10) if (days >= 1 && days <= 365 && days !== settings.windowDays) { return save({ windowDays: days }) } setWindowDays(String(settings.windowDays)) return true } const editAddress = () => { setError(undefined) setAddress(settings.returnAddress || emptyAddress) setEditingAddress(true) } const cancelAddress = () => { setError(undefined) setAddress(settings.returnAddress || emptyAddress) setEditingAddress(false) } const toggleAddress = () => { if (settings.returnAddress) { save({ returnAddress: null }) } else if (editingAddress) { cancelAddress() } else { editAddress() } } const closeModal = async () => { if (await saveWindowDays()) { cancelAddress() setOpen(false) } } const toggleEnabled = () => { if (settings.enabled) { cancelAddress() } save({ enabled: !settings.enabled }) } const rejectAddress = (message: string) => { if (message === error) { speak(message, 'assertive') } setError(message) } const saveAddress = () => { const trimmed = Object.fromEntries( Object.entries(address).map(([field, value]) => [field, value.trim()]) ) as ReturnAddress if ( !trimmed.name || !trimmed.addressLine || !trimmed.postalCode || !trimmed.city ) { rejectAddress( __( 'Fill in name, address, postal code and city.', 'posten-bring-checkout' ) ) } else if (!/^\d{4}$/.test(trimmed.postalCode)) { rejectAddress( __('The postal code must be 4 digits.', 'posten-bring-checkout') ) } else { save({ returnAddress: trimmed }) } } const addressField = (field: keyof ReturnAddress, label: string) => ( setAddress({ ...address, [field]: value })} /> ) const savedAddress = settings.returnAddress useAnnounce(open && settings.otherReturnsPlugin && otherReturnsPluginWarning) useAnnounce(open && error, 'assertive') return ( <> {__( 'Customers return items from their order. Bring emails them a return code and a QR code.', 'posten-bring-checkout' )} {settings.otherReturnsPlugin && (
{__( 'Another returns plugin is active.', 'posten-bring-checkout' )}
)} } onClick={() => setOpen(true)} /> {open && (
{settings.otherReturnsPlugin && ( {otherReturnsPluginWarning} )} {error && ( {error} )} {settings.enabled && ( save({ autoApprove: !settings.autoApprove }) } /> )} {settings.enabled && ( setWindowDays(value ?? '')} onBlur={saveWindowDays} suffix={ {__('days', 'posten-bring-checkout')} } /> )} {settings.enabled && ( {addressField( 'name', __('Name', 'posten-bring-checkout') )} {addressField( 'addressLine', __('Address line 1', 'posten-bring-checkout') )} {addressField( 'addressLine2', __( 'Address line 2 (optional)', 'posten-bring-checkout' ) )} {addressField( 'postalCode', __('Postal code', 'posten-bring-checkout') )} {addressField( 'city', __('City', 'posten-bring-checkout') )} ) : ( savedAddress && (
{savedAddress.name}
{savedAddress.addressLine} {savedAddress.addressLine2 && ( <>
{savedAddress.addressLine2} )}
{savedAddress.postalCode} {savedAddress.city}
)} ) } export default ToggleReturns