From e1faea15785a648bd2c716a265733e75179e116a Mon Sep 17 00:00:00 2001 From: peterjbone Date: Thu, 11 Jul 2024 18:00:57 -0500 Subject: [PATCH] Update DesignConfigurator.tsx --- .../configure/design/DesignConfigurator.tsx | 799 +++++++++--------- 1 file changed, 398 insertions(+), 401 deletions(-) diff --git a/src/app/configure/design/DesignConfigurator.tsx b/src/app/configure/design/DesignConfigurator.tsx index fee7f17..20b7e75 100644 --- a/src/app/configure/design/DesignConfigurator.tsx +++ b/src/app/configure/design/DesignConfigurator.tsx @@ -1,409 +1,406 @@ -'use client' - -import HandleComponent from '@/components/HandleComponent' -import { AspectRatio } from '@/components/ui/aspect-ratio' -import { ScrollArea } from '@/components/ui/scroll-area' -import { cn, formatPrice } from '@/lib/utils' -import NextImage from 'next/image' -import { Rnd } from 'react-rnd' -import { RadioGroup } from '@headlessui/react' -import { useRef, useState } from 'react' +"use client"; + +import HandleComponent from "@/components/HandleComponent"; +import { AspectRatio } from "@/components/ui/aspect-ratio"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { cn, formatPrice } from "@/lib/utils"; +import NextImage from "next/image"; +import { Rnd } from "react-rnd"; +import { RadioGroup } from "@headlessui/react"; +import { useRef, useState } from "react"; import { - COLORS, - FINISHES, - MATERIALS, - MODELS, -} from '@/validators/option-validator' -import { Label } from '@/components/ui/label' + COLORS, + FINISHES, + MATERIALS, + MODELS +} from "@/validators/option-validator"; +import { Label } from "@/components/ui/label"; import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu' -import { Button } from '@/components/ui/button' -import { ArrowRight, Check, ChevronsUpDown } from 'lucide-react' -import { BASE_PRICE } from '@/config/products' -import { useUploadThing } from '@/lib/uploadthing' -import { useToast } from '@/components/ui/use-toast' -import { useMutation } from '@tanstack/react-query' -import { saveConfig as _saveConfig, SaveConfigArgs } from './actions' -import { useRouter } from 'next/navigation' + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger +} from "@/components/ui/dropdown-menu"; +import { Button } from "@/components/ui/button"; +import { ArrowRight, Check, ChevronsUpDown } from "lucide-react"; +import { BASE_PRICE } from "@/config/products"; +import { useUploadThing } from "@/lib/uploadthing"; +import { useToast } from "@/components/ui/use-toast"; +import { useMutation } from "@tanstack/react-query"; +import { saveConfig as _saveConfig, SaveConfigArgs } from "./actions"; +import { useRouter } from "next/navigation"; interface DesignConfiguratorProps { - configId: string - imageUrl: string - imageDimensions: { width: number; height: number } + configId: string; + imageUrl: string; + imageDimensions: { width: number; height: number }; } const DesignConfigurator = ({ - configId, - imageUrl, - imageDimensions, + configId, + imageUrl, + imageDimensions }: DesignConfiguratorProps) => { - const { toast } = useToast() - const router = useRouter() - - const { mutate: saveConfig, isPending } = useMutation({ - mutationKey: ['save-config'], - mutationFn: async (args: SaveConfigArgs) => { - await Promise.all([saveConfiguration(), _saveConfig(args)]) - }, - onError: () => { - toast({ - title: 'Something went wrong', - description: 'There was an error on our end. Please try again.', - variant: 'destructive', - }) - }, - onSuccess: () => { - router.push(`/configure/preview?id=${configId}`) - }, - }) - - const [options, setOptions] = useState<{ - color: (typeof COLORS)[number] - model: (typeof MODELS.options)[number] - material: (typeof MATERIALS.options)[number] - finish: (typeof FINISHES.options)[number] - }>({ - color: COLORS[0], - model: MODELS.options[0], - material: MATERIALS.options[0], - finish: FINISHES.options[0], - }) - - const [renderedDimension, setRenderedDimension] = useState({ - width: imageDimensions.width / 4, - height: imageDimensions.height / 4, - }) - - const [renderedPosition, setRenderedPosition] = useState({ - x: 150, - y: 205, - }) - - const phoneCaseRef = useRef(null) - const containerRef = useRef(null) - - const { startUpload } = useUploadThing('imageUploader') - - async function saveConfiguration() { - try { - const { - left: caseLeft, - top: caseTop, - width, - height, - } = phoneCaseRef.current!.getBoundingClientRect() - - const { left: containerLeft, top: containerTop } = - containerRef.current!.getBoundingClientRect() - - const leftOffset = caseLeft - containerLeft - const topOffset = caseTop - containerTop - - const actualX = renderedPosition.x - leftOffset - const actualY = renderedPosition.y - topOffset - - const canvas = document.createElement('canvas') - canvas.width = width - canvas.height = height - const ctx = canvas.getContext('2d') - - const userImage = new Image() - userImage.crossOrigin = 'anonymous' - userImage.src = imageUrl - await new Promise((resolve) => (userImage.onload = resolve)) - - ctx?.drawImage( - userImage, - actualX, - actualY, - renderedDimension.width, - renderedDimension.height - ) - - const base64 = canvas.toDataURL() - const base64Data = base64.split(',')[1] - - const blob = base64ToBlob(base64Data, 'image/png') - const file = new File([blob], 'filename.png', { type: 'image/png' }) - - await startUpload([file], { configId }) - } catch (err) { - toast({ - title: 'Something went wrong', - description: - 'There was a problem saving your config, please try again.', - variant: 'destructive', - }) - } - } - - function base64ToBlob(base64: string, mimeType: string) { - const byteCharacters = atob(base64) - const byteNumbers = new Array(byteCharacters.length) - for (let i = 0; i < byteCharacters.length; i++) { - byteNumbers[i] = byteCharacters.charCodeAt(i) - } - const byteArray = new Uint8Array(byteNumbers) - return new Blob([byteArray], { type: mimeType }) - } - - return ( -
-
-
- - - -
-
-
- - { - setRenderedDimension({ - height: parseInt(ref.style.height.slice(0, -2)), - width: parseInt(ref.style.width.slice(0, -2)), - }) - - setRenderedPosition({ x, y }) - }} - onDragStop={(_, data) => { - const { x, y } = data - setRenderedPosition({ x, y }) - }} - className='absolute z-20 border-[3px] border-primary' - lockAspectRatio - resizeHandleComponent={{ - bottomRight: , - bottomLeft: , - topRight: , - topLeft: , - }}> -
- -
-
-
- -
- -