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
128 lines
3.6 KiB
JavaScript
4 years ago
|
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()
|
||
|
}
|