import React, { FC, useCallback, useRef, useState } from 'react' import { Button, Modal, Notice, SelectControl, Spinner, TextControl, } from '@wordpress/components' import { __ } from '@wordpress/i18n' import apiFetch from '@wordpress/api-fetch' import { createInterpolateElement } from '@wordpress/element' type PrinterScope = 'all' | 'mailbox' | 'other' type PrinterAssignment = { scope: PrinterScope printerId: number } type PrinterChoice = { id: number scope: PrinterScope printerId: string } type AvailablePrinter = { id: number name: string state: string | null } type PrintingSetup = { subscriptionKeyConfigured: boolean } const SCOPE_VALUES: Array = ['all', 'mailbox', 'other'] const scopeLabel = (scope: PrinterScope): string => { switch (scope) { case 'mailbox': return __( 'Home mailbox parcel – 100 x 100 mm', 'posten-bring-checkout' ) case 'other': return __('All others – 102 x 192 mm', 'posten-bring-checkout') default: return __('All products', 'posten-bring-checkout') } } const messageOf = (error: unknown, fallback: string): string => { const { code, message } = (error ?? {}) as { code?: unknown; message?: unknown } return typeof code === 'string' && typeof message === 'string' && message.trim() ? message : fallback } const asScope = (value: string): PrinterScope => SCOPE_VALUES.find(scope => scope === value) ?? 'all' const unusedScope = (choices: Array): PrinterScope => SCOPE_VALUES.find(scope => !choices.some(choice => choice.scope === scope)) ?? 'other' export declare interface AutomaticPrintingProps { className?: string } const AutomaticPrinting: FC = ({ className }) => { const [open, setOpen] = useState(false) const [key, setKey] = useState('') const [keyStored, setKeyStored] = useState(false) const [choices, setChoices] = useState>([]) const [printers, setPrinters] = useState>([]) const [loading, setLoading] = useState(false) const [loaded, setLoaded] = useState(false) const [saving, setSaving] = useState(false) const [error, setError] = useState(undefined) const nextChoiceId = useRef(0) const load = useCallback(async () => { setLoading(true) setError(undefined) setLoaded(false) try { const setup = await apiFetch({ path: '/posten-bring-checkout/printing/setup', }) const assignments = await apiFetch>({ path: '/posten-bring-checkout/printing/printers', }) setKeyStored(setup.subscriptionKeyConfigured) setChoices( assignments.length > 0 ? assignments.map(assignment => ({ id: nextChoiceId.current++, scope: assignment.scope, printerId: String(assignment.printerId), })) : [{ id: nextChoiceId.current++, scope: 'all' as PrinterScope, printerId: '' }] ) if (setup.subscriptionKeyConfigured) { setPrinters( await apiFetch>({ path: '/posten-bring-checkout/printing/available-printers', }) ) } else { setPrinters([]) } setLoaded(true) } catch (error: unknown) { setError( messageOf( error, __( 'The setup could not be loaded. Try opening the window again.', 'posten-bring-checkout' ) ) ) } finally { setLoading(false) } }, []) const openModal = () => { setOpen(true) load() } const closeModal = () => setOpen(false) const saveKey = async () => { setSaving(true) setError(undefined) try { await apiFetch({ path: '/posten-bring-checkout/printing/setup', method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ subscriptionKey: key }), }) setKey('') } catch { setError( __( 'The key was not accepted. Check that you copied the whole key from PrintNode.', 'posten-bring-checkout' ) ) return } finally { setSaving(false) } await load() } const savePrinters = async () => { setSaving(true) setError(undefined) const assignments: Array = choices .filter(choice => choice.printerId) .map(choice => ({ scope: choice.scope, printerId: Number(choice.printerId), })) try { await apiFetch({ path: '/posten-bring-checkout/printing/printers', method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(assignments), }) } catch (error: unknown) { setError( messageOf( error, __( 'The printers could not be saved. Please try again.', 'posten-bring-checkout' ) ) ) return } finally { setSaving(false) } closeModal() } const turnOff = async () => { setSaving(true) setError(undefined) try { await apiFetch({ path: '/posten-bring-checkout/printing/printers', method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify([]), }) await apiFetch({ path: '/posten-bring-checkout/printing/setup', method: 'DELETE', }) } catch { setError( __( 'Automatic printing could not be turned off. Please try again.', 'posten-bring-checkout' ) ) return } finally { setSaving(false) } await load() } const printerOptions = [ { label: __('Select printer', 'posten-bring-checkout'), value: '' }, ...printers.map(printer => ({ label: printer.state === 'online' ? printer.name : `${printer.name} – ${__('offline', 'posten-bring-checkout')}`, value: String(printer.id), })), ] const scopeOptionsFor = (choice: PrinterChoice) => SCOPE_VALUES.filter( scope => scope === choice.scope || !choices.some(it => it.scope === scope) ).map(scope => ({ label: scopeLabel(scope), value: scope })) const update = (choice: PrinterChoice, change: Partial) => setChoices(current => current.map(it => (it === choice ? { ...it, ...change } : it)) ) const remove = (choice: PrinterChoice) => setChoices(current => current.filter(it => it !== choice)) const add = () => setChoices(current => [ ...current, { id: nextChoiceId.current++, scope: unusedScope(current), printerId: '', }, ]) return (
{open && (
{error && ( {error} )}

{createInterpolateElement( __( 'Labels can be printed at the packing station when you book transport, instead of you downloading a PDF. Printing goes through PrintNode, which is the bridge between us and a printer on your own network. You create an account with them, install a small program on the machine next to the printer, and paste your key here.', 'posten-bring-checkout' ), { a: ( ), } )}

{__('Key from PrintNode', 'posten-bring-checkout')}

{keyStored ? (

{__('A key is saved.', 'posten-bring-checkout')}{' '}

) : ( )}

{__('Printers', 'posten-bring-checkout')}

{!keyStored ? (

{__( 'Your printers appear here once the key is saved.', 'posten-bring-checkout' )}

) : loading ? (

{' '} {__( 'Fetching printers from PrintNode', 'posten-bring-checkout' )}

) : printers.length === 0 ? ( {__( 'PrintNode does not see any printers. Check that the machine next to the printer is on and that the PrintNode program is running.', 'posten-bring-checkout' )} ) : ( <> {choices.map((choice, index) => (
0} __next40pxDefaultSize={true} options={printerOptions} value={choice.printerId} onChange={(value: string) => update(choice, { printerId: value }) } /> 0} __next40pxDefaultSize={true} options={scopeOptionsFor(choice)} value={choice.scope} onChange={(value: string) => update(choice, { scope: asScope(value) }) } /> {choices.length > 1 && (
))} {choices.length < SCOPE_VALUES.length && (
)} )}
{keyStored && ( )}
)}
) } export default AutomaticPrinting