You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 lines
3.6 KiB
JavaScript

import React, {useState, useRef, useEffect} from 'react'
import {DateTime} from 'luxon'
import {Button} from '~/components/form'
import styles from '~/styles/shippingLabel.module.css'
import useLocalStorage from '~/hooks/useLocalStorage'
OrderLabel.getInitialProps = async ({ctx: {axios, query: {id}}}) => {
const {data: order} = await axios.get(`/api/orders/${id}`)
return {order}
}
export default function OrderLabel({order}){
const [printCache, setPrintCache] = useLocalStorage('admin:orderlabelview', {})
const [imgLoaded, setImgLoaded] = useState(false)
const imgRef = useRef()
const currentRotation = parseInt(printCache[order.uuid]?.rotation || '0deg', 10)
// On first load, if we haven't already decided rotation for this image,
// determine based on aspect ratio
useEffect(() => {
if(printCache[order.uuid] || !imgRef.current || !imgLoaded)
return;
const {current: img} = imgRef
if(img.naturalWidth > img.naturalHeight)
setRotation(90)
}, [printCache, imgLoaded, imgRef.current])
function setRotation(deg) {
setPrintCache(printCache => {
return clearCache({
...printCache,
[order.uuid]: {
uuid: order.uuid,
rotation: deg + 'deg',
timestamp: DateTime.local().toISO()
}
})
})
}
function rotateRight() {
setRotation((currentRotation + 90) % 360)
}
function rotateLeft() {
setRotation((currentRotation - 90) % 360)
}
function print() {
printLabel(imgRef.current, currentRotation)
}
return (
<>
<h2>Print Shipping Label</h2>
<div className={styles.controls}>
<Button outline icon="rotate_left" onClick={rotateLeft}/>
<Button outline icon="print" onClick={print}/>
<Button outline icon="rotate_right" onClick={rotateRight}/>
</div>
<div className={styles.container}>
<img ref={imgRef} onLoad={() => setImgLoaded(true)} style={{transform: `rotate(${currentRotation}deg)`}} src={order.delivery.easypost.postage_label.label_url}/>
</div>
</>
)
}
// Clear out older cache entries . . . return cleared cache
function clearCache(cache) {
// Get all cache values
return Object.values(cache)
// Filter out anything older than a week
.filter(({timestamp}) => Math.abs(DateTime.fromISO(timestamp).diffNow().as('days')) < 7)
// Convert back to keyed object
.reduce((acc, obj) => ({...acc, [obj.uuid]: obj}), {})
}
function printLabel(image, rotationDegrees) {
const {naturalWidth: width, naturalHeight: height} = image
const shorterSize = width > height ? 'height' : 'width'
const longerSize = width > height ? 'width' : 'height'
const {origin, translate} = (() => {
switch(rotationDegrees) {
case 90:
case -270:
return {origin: 'left top', translate: '0%, -100%'}
case 180:
case -180:
return {origin: 'center center', translate: '0%, 0%'}
case 270:
case -90:
return {origin: 'left top', translate:'-100%, 0%'}
default:
return {origin: 'left top', translate: '0%, 0%'}
}
})()
const popup = window.open("", "Print label", "toolbar=off,width=800,height=600")
popup.document.write(`<img src="${image.getAttribute('src')}"/>`)
popup.document.write(`
<style>
html, body { width: 100%; margin: 0; padding: 0;}
img {
${shorterSize}: 4in;
${longerSize}: auto;
transform-origin: ${origin};
transform: rotate(${rotationDegrees}deg) translate(${translate});
}
</style>
`)
popup.document.close()
popup.focus()
popup.print()
popup.close()
}