Spaces:
Configuration error
Configuration error
| // frontend/src/useStore.js | |
| import { create } from "zustand"; | |
| // небольшие хелперы для запросов | |
| const postJSON = async (url, body) => { | |
| const res = await fetch(url, { | |
| method: "POST", | |
| headers: { "Content-Type": "application/json" }, | |
| body: JSON.stringify(body), | |
| }); | |
| if (!res.ok) throw new Error(await res.text()); | |
| return res.json(); | |
| }; | |
| const postFile = async (url, file) => { | |
| const fd = new FormData(); | |
| fd.append("file", file); | |
| const res = await fetch(url, { method: "POST", body: fd }); | |
| if (!res.ok) throw new Error(await res.text()); | |
| return res.json(); | |
| }; | |
| const useStore = create((set, get) => ({ | |
| // состояние | |
| model: "MT", | |
| view: "front", | |
| tile: false, | |
| offsetX: 0, | |
| offsetY: 0, | |
| scale: 1, | |
| uploadedPath: null, | |
| busy: false, | |
| lastPreviewUrls: null, | |
| lastOrderInfo: null, | |
| // сеттеры | |
| setModel: (model) => set({ model }), | |
| setView: (view) => set({ view }), | |
| setTile: (tile) => set({ tile }), | |
| setOffsetX: (offsetX) => set({ offsetX }), | |
| setOffsetY: (offsetY) => set({ offsetY }), | |
| setScale: (scale) => set({ scale }), | |
| // 1) загрузка принта | |
| async upload(file) { | |
| set({ busy: true }); | |
| try { | |
| const { path } = await postFile("/api/upload", file); | |
| set({ uploadedPath: path }); | |
| return path; | |
| } finally { | |
| set({ busy: false }); | |
| } | |
| }, | |
| // 2) построение превью из текущих контролов | |
| async spread() { | |
| const { model, view, tile, offsetX, offsetY, scale, uploadedPath } = get(); | |
| if (!uploadedPath) throw new Error("Сначала загрузите принт"); | |
| set({ busy: true }); | |
| try { | |
| const payload = { | |
| model, | |
| view, | |
| details: { | |
| print_path: uploadedPath, | |
| tile, | |
| offset_x: offsetX, | |
| offset_y: offsetY, | |
| scale, | |
| }, | |
| }; | |
| const data = await postJSON("/api/preview", payload); | |
| const urls = | |
| data.previews || | |
| (data.preview_url ? { [view]: data.preview_url } : null); | |
| set({ lastPreviewUrls: urls }); | |
| return data; | |
| } finally { | |
| set({ busy: false }); | |
| } | |
| }, | |
| // удобный комбинированный экшен под кнопку "Upload / Spread" | |
| async uploadAndSpread(file) { | |
| await get().upload(file); | |
| return get().spread(); | |
| }, | |
| // 3) создание заказа | |
| async startOrder() { | |
| const { model, view, tile, offsetX, offsetY, scale, uploadedPath } = get(); | |
| if (!uploadedPath) throw new Error("Сначала загрузите принт"); | |
| set({ busy: true }); | |
| try { | |
| const payload = { | |
| model, | |
| view, | |
| details: { | |
| print_path: uploadedPath, | |
| tile, | |
| offset_x: offsetX, | |
| offset_y: offsetY, | |
| scale, | |
| }, | |
| }; | |
| const data = await postJSON("/api/order", payload); | |
| set({ lastOrderInfo: data }); | |
| return data; | |
| } finally { | |
| set({ busy: false }); | |
| } | |
| }, | |
| })); | |
| export default useStore; |