{"version":3,"sources":["components/NavMenu.js","components/Layout.js","assets/checkers.js","assets/reserved.js","Utilities.js","DBConfig.js","DB.js","API.js","components/TooltipButton.js","components/MainView.js","assets/blankCanvas.js","components/QuiltiCanvas.js","components/BrushPicker.js","components/ColorPicker.js","components/WidthPicker.js","components/ClearButton.js","components/DoneButton.js","components/UndoButton.js","components/MainDraw.js","components/MainAdmin.js","components/GlobalErrorDialog.js","components/GeneralDialog.js","App.js","registerServiceWorker.js","index.js"],"names":["NavMenu","props","useState","collapsed","setCollapsed","Navbar","id","className","light","Container","NavbarBrand","tag","Link","to","icon","faTh","NavbarToggler","onClick","Collapse","isOpen","navbar","children","Layout","checkersImage","reservedImage","util_debugGrid","grid","debugGrid","i","length","row","j","toAdd","patchId","status","substring","push","m","console","table","map","x","util_gridColumnCount","arguments","util_gridRowCount","util_gridIsValid","columns","rows","util_calculateAllowableGridRoom","buttonSize","imageSize","minimumSpace","buttonBuffer","navBuffer","Math","max","document","getElementById","offsetHeight","clientHeight","windowWidth","min","window","innerWidth","outerWidth","windowHeight","innerHeight","outerHeight","gridRoomWidth","gridRoomHeight","gridColumns","floor","gridRows","util_gridInitialize","columnCount","rowCount","leftX","topY","y","util_createEmptyPatchDecFromPatchId","util_gridFirstOrDefault","predicate","patch","columnIndex","rowIndex","coordinates","util_patchCoordinatesFromPatchId","src","placeholderImageCheckers","util_createPatchDecFromPatch","objectStatus","imageMini","placeholderImageReserved","parseInt","split","util_extractReactState","setter","valTemp","val","util_userVisitThrottled","lastVisitThrottled","localStorage","getItem","setItem","Date","now","DBConfig","name","version","objectStoresMeta","store","storeConfig","key","storeSchema","keypath","options","unique","db_init","log","initDB","error","db_patch_insertSafe","a","db","useIndexedDB","getByIndex","add","db_patch_get","db_patchImage_get","obj","image","db_patchImage_insertSafe","api_getInitialPatchDec","axios","get","resp","data","api_getPatchDec","api_getPatchImage","patchImage","api_getPatchIdsInRange","rightX","bottomY","api_reservePatch","post","api_completePatch","interceptors","response","use","QuiltiError","Promise","reject","TooltipButton","tooltip","disabled","buttonStyle","data-tip","data-for","style","place","type","effect","offset","bottom","MainView","dbIsInitialized","setDbIsInitialized","setImageSize","fullGridCoordinates","setFullGridCoordinates","fullGrid","setFullGrid","patchIdParam","useParams","history","useHistory","mainAreaHeight","setMainAreaHeight","setButtonSize","isLoading","setIsLoading","useEffect","resolve","del","indexedDB","deleteDatabase","onsuccess","onerror","warn","findImageSizeWithRetry","backoff","imageSizeTemp","nextBackoff","setTimeout","initialPatchDec","column","patchIdsInRangeAwaited","patchIdsInRange","all","patchDecInGridMeta","p","patchDecFromApi","result","patchDecMissingFullImage","patchClick","gridLocationIsClickable","reservedPatch","imageSizeAdjustClick","factor","newImageSize","allowableGridRoom","moveGridClick","direction","resizeEventDebounced","debounce","centerPatchDec","addEventListener","removeEventListener","cssGridContainer","display","gridTemplateColumns","gridTemplateRows","fullGridContainer","width","height","NavItem","NavLink","href","faPlus","faMinus","faSpinner","spin","gridColumnStart","gridColumnEnd","gridRowStart","gridRowEnd","faAngleDoubleUp","faAngleDoubleDown","faAngleDoubleLeft","faAngleDoubleRight","data-meta","item","join","blankImage","QuiltiCanvas","color","drawMode","background","size","canvasState","setCanvasStateHistory","canvasRef","canvas","setCanvas","eventListenerAttached","setEventListenerAttached","fabric","Canvas","backgroundColor","isDrawingMode","current","on","event","renderAll","canvasImage","toDataURL","canvasStateHistory","slice","historyItemsToKeep","blankCanvas","state","Image","fromURL","img","set","left","top","freeDrawingBrush","clear","setBackgroundColor","BrushPicker","setDrawMode","faPaintBrush","faSprayCan","faDotCircle","ColorPicker","setColor","setIsOpen","position","faSquare","colors","onChangeComplete","colorParam","chooseColor","hex","triangle","WidthPicker","setWidth","Slider","step","defaultValue","snapToStep","onChange","widthParam","showValue","ClearButton","faTrashAlt","Dialog","open","onClose","aria-labelledby","aria-describedby","DialogTitle","DialogContent","DialogContentText","DialogActions","DoneButton","save","faSave","UndoButton","undo","faUndoAlt","MainDraw","mainAreaWidth","setMainAreaWidth","setPatchIdsInRange","patchSize","setPatchSize","setBackground","setCanvasState","useRef","pcfp","replace","imageUncompressed","imageObj","decode","miniCanvas","createElement","miniCtx","getContext","drawImage","mediumCanvas","mediumCtx","respPatchId","calculateFullGridClass","ret","pop","previousState","MainAdmin","setPatchId","setPatchImage","creatorIp","setCreatorIp","reqStatus","setReqStatus","checkImage","removeImage","banUser","delete","fieldMargin","marginTop","margin","TextField","label","value","e","target","GlobalErrorDialog","errorCode","setErrorCode","code","faExclamationTriangle","marginRight","403","404","409","GeneralDialog","title","setTitle","message","setMessage","QuiltiDialog","App","exact","path","component","isLocalhost","Boolean","location","hostname","match","registerValidSW","swUrl","navigator","serviceWorker","register","then","registration","onupdatefound","installingWorker","installing","onstatechange","controller","catch","baseUrl","getElementsByTagName","getAttribute","rootElement","ReactDOM","render","basename","URL","process","origin","fetch","headers","indexOf","ready","unregister","reload","checkValidServiceWorker","registerServiceWorker"],"mappings":"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","file":"static/js/main.c94f6ae8.chunk.js","sourcesContent":["import React, { useState } from 'react';\r\nimport { Collapse, Container, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink } from 'reactstrap';\r\nimport { Link } from 'react-router-dom';\r\nimport './NavMenu.css';\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\r\nimport { faTh } from '@fortawesome/free-solid-svg-icons';\r\n\r\nexport function NavMenu(props) {\r\n const [collapsed, setCollapsed] = useState(true);\r\n\r\n let toggleNavbar = () => {\r\n setCollapsed(collapsed => !collapsed);\r\n };\r\n\r\n return (\r\n
\r\n \r\n \r\n \r\n Quilti\r\n \r\n \r\n \r\n
    {props.children}
\r\n
\r\n
\r\n
\r\n
\r\n );\r\n}\r\n","import React, { Component } from 'react';\r\nimport { NavMenu } from './NavMenu';\r\n\r\nexport function Layout(props) {\r\n return (\r\n
\r\n {/* */}\r\n
{props.children}
\r\n
\r\n );\r\n}\r\n","let checkersImage =\r\n 'data:image/png;base64,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';\r\n\r\nexport default checkersImage;\r\n","let reservedImage =\r\n 'data:image/png;base64,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/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAXC5JREFUeNrs3UlwHVd+Jvovh5uZ92bmHTDPxEAAJABOogYOkkhKKqnK5epwVXRHL7pXL97rcHT0wove9KKjw956401Hh+x+7uiInvzshcN2SWJJokRSoiSKGjiTmEgCIDEPd745v0UCJFUiRZAAiAvc7xdRC5dZR1TezPPlOXnO/wjvvvtugFX4N//m36zmj+Ev//IvwfbYHttje2yP7bG959ueCCIiItryGOhEREQMdCIiImKgExEREQOdiIiIGOhEREQMdCIiImKgExEREQOdiIiIHiYEQbCqSnGs4MP22B7bY3tsj+2Vb3scoRMREW0DDHQiIiIGOhERETHQiYiIiIFOREREDHQiIiIGOhERETHQiYiIiIFORERED5NZcYftsT22x/bYHtvb+u1xhE5ERLQNMNCJiIgY6ERERMRAJyIiIgY6ERERMdCJiIgY6ERERMRAJyIiIgY6ERERPUwIgiBYzR9kBR+2x/bYHttje2yvfNvjCJ2IiGgbYKATEREx0ImIiIiBTkRERAx0IiIiYqATEREx0ImIiIiBTkRERAx0IiIiepjMijtsj+2xPbbH9tje1m+PI3QiIqJtgIFORETEQCciIiIGOhERETHQiYiIiIFORETEQCciIiIGOhERETHQiYiI6GFCEATBav4gK/iwPbbH9tge22N75dseR+hERETbAAOdiIiIgU5EREQMdCIiImKgExEREQOdiIiIgU5EREQMdCIiImKgExER0cNkVtxhe2yP7bE9tsf2tn57HKETERFtAwx0IiIiBjoREREx0ImIiIiBTkRERAx0IiIiBjoREREx0ImIiIiBTkRERA8TgiAIVvMHWcGH7bE9tsf22B7bK9/2OEInIiLaBhjoREREDHQiIiJioBMREREDnYiIiBjoREREDHQiIiJioBMREREDnYiIiB4ms+IO22N7bI/tsT22t/Xb4widiIhoG2CgExERMdCJiIiIgU5EREQMdCIiImKgExERMdCJiIiIgU5ERETrSOYlICLafIHnIbAs+KUSBEGAEI0CQQAIAi8OrYoQBEGwmj/ICj5sj+2xPba3Ae0FAUTXhZTPQ52bg7K4iEAUYVdX41/+yZ9ASqUgyPJPBjt/D7bHEToR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X/5LxF5+GXIyib/8q7/i78H22B7bq8j2OEKnDScIAgRVhVxdDbm2FmIstrZv3MuL86J798I8cQLRPXsgJRLcokZElT1C5yWgDSeKkJNJRPftgzE+Di+bRen6dfjPUi1OEMLSrj09MF5/HfqLL0KureV3cyJioPMS0HPJ9FgMWnc3/DffhF8sIiiVYI2MwH/Kw14ERYHS3Azj0CEYR48i0trK7+ZERAx0ep6jdDEeR7S/H4Fth6HuOCiMjq5+kZwoQmZpVyIiBjptLkGSICWTiO3bh6BUQmBZSC8uQllYeHIZWEGAFI8j2tcH49gxRFnalYiIgU6bGOqyDKm6GrEXX0Tgebh57RqMwUEoS0s/GeqipkHt6IDx+uswDh9GpLGRU+1ERA/3k7wEtBkjdbm2FrEXX0S6vx/5zk448TiCxyxsCyQJkYYG6IcOwXj1VR6JSkTEETqVU6hH6uqQ7+iA6LoQHQf6rVuQs9kflIUNBAGuriO6f3/43Xz3bkgs7UpExECnckn0sHysG48j19l5f7pdm5qC4DgQlle++7IMq7YW5okTiB04ALmqit/NiYge1a0Gwer2DLGCD9vbqPb8UgnO+DgKly7BHh2FXyhg5bYUVRWRlha8NzwMq6YGvqL85OicvwfbY3tsr1Lb4widNp2oaVB27IBUXY3g0CEED5+XLooQNQ3W//f/wZdlTrUTETHQqZwJihJOpz9qwkgQ4HNFOxERA522UrJzBE5E9Cy4uoiIiIiBTkRERAx0IiIiYqATERERA52IiIiBTkREROVDZsUdtsf22B7bY3tsb+u3xxE6ERHRNsBAJyIiYqATERERA52IiIgY6ERERMRAJyIiYqATERERA52IiIgY6ERERPQwIQiCYDV/kBV82B7bY3tsj+2xvfJtjyN0IiKibYCBTkRExEAnIiIiBjoREREx0ImIiIiBTkRExEAnIiIiBjoREREx0ImIiOhhMivusD22x/bYHttje1u/PY7QiYiItgEGOhEREQOdiIiIGOhERETEQCciIiIGOhEREQOdiIiIGOhERETEQCciIqKHCUEQBKv5g6zgw/bYHttje2yP7ZVvexyhExERbQMMdCIiIgY6ERERMdCJiIiIgU5EREQMdCIiIgY6ERERMdCJiIiIgU5EREQPk1lxh+2xPbbH9tge29v67XGETkREtA0w0ImIiBjoRERExEAnIiIiBjoREREx0ImIiBjoRERExEAnIiIiBjoRERE9TAiCIFjNH2QFH7bH9tge22N7bK982+MInYiIaBtgoBMRETHQiYiIiIFOREREDHQiIiJioBMRETHQiYiIiIFOREREDHQiIiJ6mMyKO2yP7bE9tsf22N7Wb48jdCIiom2AgU5ERMRAJyIiIgY6ERERMdCJiIiIgU5ERMRAJyIiIgY6ERERMdCJiIjoYUIQBMFq/iAr+LA9tsf22B7bY3vl2x5H6ERERNsAA52IiIiBTkRERAx0IiIiYqATERERA52IiIiBTkRERAx0IiIiYqATERHRw/7/AQAnnRobz8gUNAAAAABJRU5ErkJggg==';\r\n\r\nexport default reservedImage;\r\n","import placeholderImageCheckers from './assets/checkers.js';\r\nimport placeholderImageReserved from './assets/reserved.js';\r\n\r\n//// Grid Utilities \\\\\\\\\r\nexport function util_debugGrid(grid) {\r\n let debugGrid = [];\r\n for (let i = 0; i < grid.length; i++) {\r\n let row = [];\r\n for (let j = 0; j < grid[0].length; j++) {\r\n //row.push(i + '-' + j);\r\n let toAdd = grid[i][j].patchId;\r\n if (grid[i][j].status === 'reserved' || grid[i][j].status === 'partial' || grid[i][j].status === 'full') {\r\n toAdd += ' - ' + grid[i][j].status.substring(0, 4);\r\n }\r\n row.push(toAdd);\r\n }\r\n debugGrid.push(row);\r\n }\r\n\r\n let transpose = m => m[0].map((x, i) => m.map(x => x[i]));\r\n console.table(transpose(debugGrid));\r\n}\r\n\r\nexport function util_gridColumnCount(grid) {\r\n if (arguments.length !== 1) throw 'invalid args in util_gridColumnCount';\r\n if (!grid) throw 'invalid args in util_gridColumnCount';\r\n\r\n return grid.length;\r\n}\r\n\r\nexport function util_gridRowCount(grid) {\r\n if (arguments.length !== 1) throw 'invalid args in util_gridRowCount';\r\n if (!grid || !grid[0]) throw 'invalid args in util_gridRowCount';\r\n\r\n return grid[0].length;\r\n}\r\n\r\nexport function util_gridIsValid(grid) {\r\n let columns = util_gridColumnCount(grid);\r\n let rows = util_gridRowCount(grid);\r\n\r\n return columns > 0 && rows > 0;\r\n}\r\n\r\nexport function util_calculateAllowableGridRoom(buttonSize, imageSize, minimumSpace) {\r\n if (arguments.length !== 3) throw 'invalid args in util_calculateAllowableGridRoom';\r\n if (buttonSize <= 0 || imageSize <= 0) throw 'invalid args in util_calculateAllowableGridRoom';\r\n\r\n let buttonBuffer = 2 * buttonSize;\r\n let navBuffer = Math.max(document.getElementById('nav').offsetHeight, document.getElementById('nav').clientHeight);\r\n\r\n let windowWidth = Math.min(window.innerWidth, window.outerWidth); // idk man, some browsers are just weird like that\r\n let windowHeight = Math.min(window.innerHeight, window.outerHeight);\r\n\r\n let gridRoomWidth = windowWidth - buttonBuffer;\r\n let gridRoomHeight = windowHeight - buttonBuffer - navBuffer;\r\n if (gridRoomWidth < minimumSpace || gridRoomHeight < minimumSpace) {\r\n throw 'oops, not enough room for any size grid! ' + gridRoomWidth + 'x' + gridRoomHeight;\r\n }\r\n\r\n let gridColumns = Math.floor(gridRoomWidth / imageSize);\r\n let gridRows = Math.floor(gridRoomHeight / imageSize);\r\n return { gridColumns, gridRows };\r\n}\r\n\r\nexport function util_gridInitialize(columnCount, rowCount, leftX, topY) {\r\n if (arguments.length !== 4) throw 'invalid args in util_gridInitialize';\r\n if (columnCount <= 0 || rowCount <= 0) throw 'invalid args in util_gridInitialize';\r\n\r\n let x = leftX;\r\n let y = topY;\r\n let grid = [];\r\n for (let i = 0; i < columnCount; i++) {\r\n let row = [];\r\n y = topY;\r\n for (let j = 0; j < rowCount; j++) {\r\n row.push(util_createEmptyPatchDecFromPatchId(x + 'x' + y));\r\n y--;\r\n }\r\n grid.push(row);\r\n x++;\r\n }\r\n\r\n return grid;\r\n}\r\n\r\nexport function util_gridFirstOrDefault(grid, predicate) {\r\n if (arguments.length !== 2) throw 'invalid args in util_gridFirstOrDefault';\r\n if (!util_gridIsValid(grid)) throw 'invalid grid in util_gridFirstOrDefault';\r\n\r\n let columnCount = util_gridColumnCount(grid);\r\n let rowCount = util_gridRowCount(grid);\r\n for (let i = 0; i < columnCount; i++) {\r\n for (let j = 0; j < rowCount; j++) {\r\n if (predicate(grid[i][j])) {\r\n return { patch: grid[i][j], columnIndex: i, rowIndex: j };\r\n //return grid[i][j];\r\n }\r\n }\r\n }\r\n}\r\n\r\n//// Patch Utilities \\\\\\\\\r\nexport function util_createEmptyPatchDecFromPatchId(patchId) {\r\n if (arguments.length !== 1) throw 'invalid args in util_createEmptyPatchDecFromPatchId';\r\n\r\n let coordinates = util_patchCoordinatesFromPatchId(patchId);\r\n\r\n return {\r\n patchId,\r\n x: coordinates.x,\r\n y: coordinates.y,\r\n src: placeholderImageCheckers,\r\n status: 'empty',\r\n };\r\n}\r\n\r\nexport function util_createPatchDecFromPatch(patch) {\r\n if (arguments.length !== 1) throw 'invalid args in util_createPatchDecFromPatch';\r\n if (!patch) throw 'invalid args in util_createPatchDecFromPatch';\r\n if (patch.objectStatus !== 'ACT' && patch.objectStatus !== 'RES') throw 'invalid args in api_createPatchDecFromPatch';\r\n\r\n return {\r\n patchId: patch.patchId,\r\n x: patch.x,\r\n y: patch.y,\r\n src: patch.objectStatus === 'ACT' ? patch.imageMini : placeholderImageReserved,\r\n status: patch.objectStatus === 'ACT' ? 'partial' : 'reserved',\r\n };\r\n}\r\n\r\nexport function util_patchCoordinatesFromPatchId(patchId) {\r\n if (arguments.length !== 1) throw 'invalid args in util_patchComponentsFromPatchId';\r\n\r\n return {\r\n x: parseInt(patchId.split('x')[0], 10),\r\n y: parseInt(patchId.split('x')[1], 10),\r\n };\r\n}\r\n\r\n//// Misc Utilities \\\\\\\\\r\n// Take advantage of the fact that our setter maintain access to the latest React state values\r\n// to pull it out when we've lost context (event listeners, setTimeout, etc)\r\nexport function util_extractReactState(setter) {\r\n if (arguments.length !== 1) throw 'invalid args in util_extractReactState';\r\n let valTemp;\r\n setter(val => {\r\n valTemp = val;\r\n return val;\r\n });\r\n return valTemp;\r\n}\r\n\r\n// Interface with localstorage and track the date of their last visit, throttled at 24 hours.\r\n// Return true if it's been more than 24 hours otherwise false\r\n// We use this to determine if they should have their local DB cleared out.\r\nexport function util_userVisitThrottled() {\r\n let lastVisitThrottled = localStorage.getItem('lastVisitThrottled');\r\n if (!lastVisitThrottled) {\r\n localStorage.setItem('lastVisitThrottled', Date.now());\r\n return false;\r\n }\r\n\r\n lastVisitThrottled = parseInt(lastVisitThrottled, 10);\r\n let oneDay = 24 * 60 * 60 * 1000;\r\n if (Date.now() - oneDay > lastVisitThrottled) {\r\n localStorage.setItem('lastVisitThrottled', Date.now());\r\n return true;\r\n }\r\n return false;\r\n}\r\n","export const DBConfig = {\r\n name: 'QuiltiDb',\r\n version: 1,\r\n objectStoresMeta: [\r\n {\r\n store: 'patches',\r\n storeConfig: { key: 'patchId' },\r\n storeSchema: [\r\n { name: 'patchId', keypath: 'patchId', options: { unique: true } },\r\n { name: 'x', keypath: 'x', options: { unique: false } },\r\n { name: 'y', keypath: 'y', options: { unique: false } },\r\n { name: 'imageMini', keypath: 'imageMini', options: { unique: false } },\r\n { name: 'objectStatus', keypath: 'objectStatus', options: { unique: false } },\r\n ],\r\n },\r\n {\r\n store: 'patchImages',\r\n storeConfig: { key: 'patchId' },\r\n storeSchema: [\r\n { name: 'patchId', keypath: 'patchId', options: { unique: true } },\r\n { name: 'image', keypath: 'image', options: { unique: false } },\r\n ],\r\n },\r\n ],\r\n};\r\n","import { initDB, useIndexedDB } from 'react-indexed-db';\r\nimport { DBConfig } from './DBConfig';\r\n\r\n// DB ETHOS\r\n// In order to keep this from getting chaotic, this cache serves as a layer to represent the\r\n// results from api requests and nothing more. Nothing going in or coming out should contain\r\n// anything more or less than you'd receive from the server. We also only ever store objects\r\n// once they're in their \"completed\" state. This means:\r\n// - No decorated properties\r\n// - No exotic data types\r\n// - Patches contain an east/south/west/north and are Active (not enforced here)\r\n// - PatchImages contain an image (should always be the case in my current architecture)\r\n// This might sacrifice some efficiency but I'll take sanity over performance any day of the week.\r\n\r\nexport function db_init() {\r\n console.log('init');\r\n try {\r\n initDB(DBConfig);\r\n } catch {\r\n console.error('failed to initialize DB (probably already initialized - HMR related error)');\r\n }\r\n}\r\n\r\nexport async function db_patch_insertSafe(patch) {\r\n const db = useIndexedDB('patches');\r\n let existingVal = await db.getByIndex('patchId', patch.patchId);\r\n if (!existingVal) {\r\n db.add(patch, patch.patchId);\r\n }\r\n}\r\n\r\nexport async function db_patch_get(patchId) {\r\n const db = useIndexedDB('patches');\r\n //var ret = await db.getByID(patchId);\r\n var patch = await db.getByIndex('patchId', patchId);\r\n return patch;\r\n}\r\n\r\nexport async function db_patchImage_get(patchId) {\r\n const db = useIndexedDB('patchImages');\r\n let obj = await db.getByIndex('patchId', patchId);\r\n return obj && obj.image;\r\n}\r\n\r\nexport async function db_patchImage_insertSafe(patchId, image) {\r\n const db = useIndexedDB('patchImages');\r\n let existingVal = await db.getByIndex('patchId', patchId);\r\n if (!existingVal) {\r\n db.add({ image, patchId }, patchId);\r\n }\r\n}\r\n\r\nexport function db_deleteDatabase() {\r\n return new Promise((resolve, reject) => {\r\n var del = indexedDB.deleteDatabase(DBConfig.name);\r\n del.onsuccess = () => {\r\n console.log('DB deleted');\r\n resolve();\r\n };\r\n del.onerror = () => {\r\n console.warn('Failed to delete DB');\r\n // Currently we're only doing this as a measure to keep using from seeing seldom deleted patches\r\n // This is rare wont cause any issues if it fails so we dont call reject() here\r\n resolve();\r\n };\r\n });\r\n}\r\n","import axios from 'axios';\r\nimport { db_patchImage_get, db_patchImage_insertSafe, db_patch_get, db_patch_insertSafe } from './DB';\r\nimport { util_createEmptyPatchDecFromPatchId, util_createPatchDecFromPatch } from './Utilities';\r\n\r\n// This layer is responsible for all requests to the server and getting/storing in indexedDb when appropriate\r\n// Patches are always returned in our frontend/friendly way with decorated properties\r\n// They are never stored in the DB with these features, though\r\n\r\n// 2 main objects at play here, \"Patch\" and \"PatchDec\". PatchDec being the same as a Patch except\r\n// customized / decorated specifically for our uses in the frontend.\r\n\r\n// Patch:\r\n// patchId string\r\n// x int\r\n// y int\r\n// imageMini string\r\n// objectStatus string\r\n\r\n//PatchDec:\r\n// patchId string\r\n// x int\r\n// y int\r\n// src string\r\n// status string (empty, reserved, partial, full)\r\n// PatchDec status is similar but different from the db based statuses in that these contain extra states\r\n// (empty, partial, full) so we can add in empty patches in our grid and to track it's progress\r\n// through the app when applying full size images (partial // full)\r\n\r\naxios.interceptors.response.use(\r\n response => response,\r\n error => {\r\n window.QuiltiError(error.response.status);\r\n return Promise.reject(error);\r\n }\r\n);\r\n\r\nexport async function api_getInitialPatchDec() {\r\n if (arguments.length !== 0) throw 'invalid args in api_getInitialPatchDec';\r\n\r\n let resp = await axios.get('/api/Patch');\r\n return util_createPatchDecFromPatch(resp.data);\r\n}\r\n\r\nexport async function api_getPatchDec(patchId) {\r\n if (arguments.length !== 1) throw 'invalid args in api_getPatchDec';\r\n\r\n let patch = await db_patch_get(patchId);\r\n\r\n if (!patch) {\r\n let resp = await axios.get('/api/Patch/' + patchId);\r\n patch = resp.data;\r\n\r\n if (patch && patch.objectStatus === 'ACT') await db_patch_insertSafe(patch);\r\n }\r\n\r\n // if we still don't have a patch by this point we're looking at an empty spot\r\n if (!patch) return util_createEmptyPatchDecFromPatchId(patchId);\r\n\r\n return util_createPatchDecFromPatch(patch);\r\n}\r\n\r\nexport async function api_getPatchImage(patchId) {\r\n if (arguments.length !== 1) throw 'invalid args in api_getPatchImage';\r\n\r\n let patchImage = await db_patchImage_get(patchId);\r\n\r\n if (!patchImage) {\r\n let resp = await axios.get('/api/PatchImage/' + patchId);\r\n patchImage = resp.data;\r\n\r\n if (patchImage) await db_patchImage_insertSafe(patchId, patchImage);\r\n }\r\n\r\n return patchImage;\r\n}\r\n\r\nexport async function api_getPatchIdsInRange(leftX, rightX, topY, bottomY) {\r\n if (arguments.length !== 4) throw 'invalid args in api_getPatchDec';\r\n\r\n let resp = await axios.get(`/api/PatchGroup/${leftX}/${rightX}/${topY}/${bottomY}`);\r\n return resp.data;\r\n}\r\n\r\nexport async function api_reservePatch(patchId) {\r\n if (arguments.length !== 1) throw 'invalid args in api_getPatchDec';\r\n\r\n let resp = await axios.post('/api/Patch/' + patchId);\r\n return resp.data;\r\n}\r\n\r\nexport async function api_completePatch(patchId, image, imageMini) {\r\n if (arguments.length !== 3) throw 'invalid args in api_completedPatch';\r\n if (!patchId || !image || !imageMini) throw 'invalid args in api_completedPatch';\r\n\r\n let resp = await axios.patch('/api/Patch/', { patchId, image, imageMini });\r\n return resp.data;\r\n}\r\n","import React, { useEffect, useState } from 'react';\r\nimport ReactTooltip from 'react-tooltip';\r\n\r\nexport function TooltipButton({ tooltip, onClick, disabled, children, buttonStyle }) {\r\n return (\r\n <>\r\n \r\n {!disabled && (\r\n \r\n {tooltip}\r\n \r\n )}\r\n \r\n );\r\n}\r\n","import React, { useEffect, useState } from 'react';\r\nimport {\r\n util_calculateAllowableGridRoom,\r\n util_debugGrid,\r\n util_gridColumnCount,\r\n util_gridRowCount,\r\n util_gridInitialize,\r\n util_gridFirstOrDefault,\r\n util_extractReactState,\r\n util_userVisitThrottled,\r\n} from '../Utilities';\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\r\nimport {\r\n faAngleDoubleUp,\r\n faAngleDoubleDown,\r\n faAngleDoubleLeft,\r\n faAngleDoubleRight,\r\n faPlus,\r\n faMinus,\r\n faSpinner,\r\n} from '@fortawesome/free-solid-svg-icons';\r\nimport { db_deleteDatabase, db_init } from '../DB';\r\nimport { NavMenu } from './NavMenu';\r\nimport { NavItem, NavLink } from 'reactstrap';\r\nimport { useParams, useHistory } from 'react-router-dom';\r\nimport { api_getInitialPatchDec, api_getPatchDec, api_getPatchIdsInRange, api_getPatchImage, api_reservePatch } from '../API';\r\nimport { debounce } from 'lodash';\r\nimport { TooltipButton } from './TooltipButton';\r\n\r\nexport function MainView() {\r\n const [dbIsInitialized, setDbIsInitialized] = useState(false);\r\n const [imageSize, setImageSize] = useState(null);\r\n const [fullGridCoordinates, setFullGridCoordinates] = useState(null);\r\n const [fullGrid, setFullGrid] = useState(null);\r\n const { patchIdParam } = useParams();\r\n const history = useHistory();\r\n // Layout aids\r\n const [mainAreaHeight, setMainAreaHeight] = useState(1);\r\n const [buttonSize, setButtonSize] = useState(30);\r\n const [isLoading, setIsLoading] = useState(true);\r\n\r\n //// Main process flow \\\\\\\\\r\n // https://app.creately.com/diagram/XnWD2VGuOky/edit\r\n // We daisy chain through stages 0 => 3, the tail of each kicking off the next, each stage dependant on the one before it.\r\n // We break it into stages so that our user interaction can pipe in at key points and kick off just the remainder of the chain\r\n\r\n // Stage 0 - Init \\\\\r\n useEffect(() => {\r\n (async () => {\r\n if (!dbIsInitialized) {\r\n if (util_userVisitThrottled()) await db_deleteDatabase();\r\n\r\n db_init();\r\n // only needed because of HMR, if this is a prod build we can pull it out\r\n setDbIsInitialized(true);\r\n }\r\n\r\n // Determine the suitable starting imageSize based on fitting a minimum of 2 rows/columns in users current screen\r\n findImageSizeWithRetry(10);\r\n })();\r\n }, []);\r\n\r\n // Stage 0-B\r\n // If the page is opened in a new tab, we dont get accurate/valid size until the user actually hits the page\r\n // So we do an exponential backoff of retries until we hit a valid screen size.\r\n let findImageSizeWithRetry = backoff => {\r\n try {\r\n let imageSizeTemp = 400;\r\n let gridColumns = 0;\r\n let gridRows = 0;\r\n while (gridColumns < 2 || gridRows < 2) {\r\n imageSizeTemp = imageSizeTemp / 2;\r\n ({ gridColumns, gridRows } = util_calculateAllowableGridRoom(buttonSize, imageSizeTemp, 100));\r\n }\r\n setImageSize(imageSizeTemp);\r\n } catch {\r\n console.warn(`unable to calc imageSize, retrying after ${backoff} ms`);\r\n let nextBackoff = backoff * 2 < 5000 ? backoff * 2 : 5000;\r\n setTimeout(() => findImageSizeWithRetry(nextBackoff), backoff);\r\n }\r\n };\r\n\r\n // Stage 1 - imageSize callback \\\\\r\n useEffect(() => {\r\n if (!imageSize) return;\r\n (async () => {\r\n setMainAreaHeight(window.innerHeight - document.getElementById('nav').offsetHeight);\r\n\r\n let initialPatchDec;\r\n if (patchIdParam) {\r\n // coming in from /view/x page\r\n initialPatchDec = await api_getPatchDec(patchIdParam);\r\n } else if (fullGrid) {\r\n // on user image size adjustment, grab the closest one to the center\r\n let column = Math.floor(util_gridColumnCount(fullGrid) / 2);\r\n let row = Math.floor(util_gridRowCount(fullGrid) / 2);\r\n initialPatchDec = fullGrid[column][row];\r\n } else {\r\n // initial load\r\n initialPatchDec = await api_getInitialPatchDec();\r\n }\r\n\r\n // Figure out the size of our grid and the appropriate global coordinates\r\n let { gridColumns, gridRows } = util_calculateAllowableGridRoom(buttonSize, imageSize, 100);\r\n\r\n let leftX = initialPatchDec.x - Math.floor(gridColumns / 2);\r\n let rightX = leftX + gridColumns - 1;\r\n let topY = initialPatchDec.y + Math.floor(gridRows / 2);\r\n let bottomY = topY - gridRows + 1;\r\n setFullGridCoordinates({ leftX, rightX, topY, bottomY });\r\n })();\r\n }, [imageSize]);\r\n\r\n // Stage 2 - fullGridCoordinates Callback \\\\\r\n useEffect(() => {\r\n if (!fullGridCoordinates) return;\r\n (async () => {\r\n let patchIdsInRangeAwaited = api_getPatchIdsInRange(\r\n fullGridCoordinates.leftX,\r\n fullGridCoordinates.rightX,\r\n fullGridCoordinates.topY,\r\n fullGridCoordinates.bottomY\r\n );\r\n\r\n let columnCount = fullGridCoordinates.rightX - fullGridCoordinates.leftX + 1;\r\n let rowCount = fullGridCoordinates.topY - fullGridCoordinates.bottomY + 1;\r\n\r\n // Build the empty grid\r\n let grid = util_gridInitialize(columnCount, rowCount, fullGridCoordinates.leftX, fullGridCoordinates.topY);\r\n //util_debugGrid(grid);\r\n\r\n // Finish waiting for the request to come back\r\n let patchIdsInRange = await patchIdsInRangeAwaited;\r\n\r\n // Fill in all the ones that we know contain something\r\n await Promise.all(\r\n patchIdsInRange.map(async patchId => {\r\n //console.log('Starting to get patch...', patchId); //check for parallelism\r\n let patchDecInGridMeta = util_gridFirstOrDefault(grid, p => p.patchId === patchId);\r\n let patchDecFromApi = await api_getPatchDec(patchDecInGridMeta.patch.patchId);\r\n grid[patchDecInGridMeta.columnIndex][patchDecInGridMeta.rowIndex] = patchDecFromApi;\r\n //console.log('Finished setting patch...', patchId);\r\n })\r\n );\r\n\r\n //util_debugGrid(grid);\r\n setFullGrid(grid);\r\n })();\r\n }, [fullGridCoordinates]);\r\n\r\n // Stage 3 - fullGrid Callback \\\\\r\n useEffect(() => {\r\n if (!fullGrid) return;\r\n (async () => {\r\n setIsLoading(false);\r\n let result = util_gridFirstOrDefault(fullGrid, patch => patch.status === 'partial');\r\n let patchDecMissingFullImage = result && result.patch;\r\n if (patchDecMissingFullImage) {\r\n let image = await api_getPatchImage(patchDecMissingFullImage.patchId);\r\n patchDecMissingFullImage.src = image;\r\n patchDecMissingFullImage.status = 'full';\r\n setFullGrid(fullGrid => [...fullGrid]);\r\n\r\n //util_debugGrid(fullGrid);\r\n }\r\n })();\r\n }, [fullGrid]);\r\n\r\n //// User interaction / onClick bindings \\\\\\\\\r\n let patchClick = async patch => {\r\n if (!gridLocationIsClickable(patch)) return;\r\n\r\n try {\r\n let reservedPatch = await api_reservePatch(patch.patchId);\r\n history.push('/draw/' + reservedPatch);\r\n } catch (error) {\r\n if (error.response.status === 409) {\r\n // User tried to hit a patch that was already reserved, refresh the grid\r\n setFullGridCoordinates(fullGridCoordinates => ({ ...fullGridCoordinates }));\r\n }\r\n }\r\n };\r\n\r\n let imageSizeAdjustClick = factor => {\r\n if (isLoading) return;\r\n\r\n // Ensure we're not beyond our fixed min/max and that we have room for this size grid\r\n let newImageSize = factor > 0 ? imageSize * 2 : imageSize / 2;\r\n if (newImageSize < 50 || newImageSize > 800) return;\r\n let allowableGridRoom = util_calculateAllowableGridRoom(buttonSize, newImageSize, 100);\r\n if (allowableGridRoom.gridColumns < 2 || allowableGridRoom.gridRows < 2) return;\r\n\r\n setIsLoading(true);\r\n setImageSize(newImageSize);\r\n };\r\n\r\n let moveGridClick = direction => {\r\n if (isLoading) return;\r\n\r\n setFullGridCoordinates(coordinates => {\r\n switch (direction) {\r\n case 'up':\r\n coordinates.topY++;\r\n coordinates.bottomY++;\r\n break;\r\n case 'down':\r\n coordinates.topY--;\r\n coordinates.bottomY--;\r\n break;\r\n case 'left':\r\n coordinates.leftX--;\r\n coordinates.rightX--;\r\n break;\r\n case 'right':\r\n coordinates.leftX++;\r\n coordinates.rightX++;\r\n break;\r\n }\r\n return { ...coordinates };\r\n });\r\n };\r\n\r\n let resizeEventDebounced = debounce(() => {\r\n let fullGrid = util_extractReactState(setFullGrid);\r\n if (!fullGrid) return;\r\n\r\n let column = Math.floor(util_gridColumnCount(fullGrid) / 2);\r\n let row = Math.floor(util_gridRowCount(fullGrid) / 2);\r\n let centerPatchDec = fullGrid[column][row];\r\n\r\n // Figure out the size of our grid and the appropriate global coordinates\r\n let buttonSize = util_extractReactState(setButtonSize);\r\n let imageSize = util_extractReactState(setImageSize);\r\n let { gridColumns, gridRows } = util_calculateAllowableGridRoom(buttonSize, imageSize, 100);\r\n if (gridColumns < 2 || gridRows < 2) return;\r\n\r\n let leftX = centerPatchDec.x - Math.floor(gridColumns / 2);\r\n let rightX = leftX + gridColumns - 1;\r\n let topY = centerPatchDec.y + Math.floor(gridRows / 2);\r\n let bottomY = topY - gridRows + 1;\r\n setFullGridCoordinates({ leftX, rightX, topY, bottomY });\r\n }, 1000);\r\n useEffect(() => {\r\n window.addEventListener('resize', resizeEventDebounced);\r\n return () => {\r\n window.removeEventListener('resize', resizeEventDebounced);\r\n };\r\n }, []);\r\n\r\n //// Dynamic CSS styling / display aids \\\\\\\\\r\n const cssGridContainer = {\r\n display: 'grid',\r\n gridTemplateColumns: fullGrid ? `${buttonSize}px ${imageSize * util_gridColumnCount(fullGrid)}px ${buttonSize}px` : '',\r\n gridTemplateRows: fullGrid ? `${buttonSize}px ${imageSize * util_gridRowCount(fullGrid)}px ${buttonSize}px` : '',\r\n };\r\n\r\n const fullGridContainer = {\r\n display: 'flex',\r\n width: fullGrid ? imageSize * util_gridColumnCount(fullGrid) : 0,\r\n height: fullGrid ? imageSize * util_gridRowCount(fullGrid) : 0,\r\n };\r\n\r\n let gridLocationIsClickable = patch => {\r\n return patch.status === 'empty';\r\n };\r\n\r\n return (\r\n
\r\n \r\n \r\n \r\n imageSizeAdjustClick(1)}>\r\n \r\n \r\n \r\n \r\n \r\n \r\n imageSizeAdjustClick(-1)}>\r\n \r\n \r\n \r\n \r\n \r\n
\r\n {isLoading ? (\r\n \r\n ) : (\r\n
\r\n moveGridClick('up')}>\r\n \r\n \r\n moveGridClick('down')}>\r\n \r\n \r\n moveGridClick('left')}>\r\n \r\n \r\n moveGridClick('right')}>\r\n \r\n \r\n\r\n
\r\n {fullGrid.map((column, i) => {\r\n return (\r\n
item && item.patchId).join() + '-' + i}>\r\n {column.map((patch, j) => (\r\n patchClick(patch)}\r\n data-meta={patch.patchId}\r\n />\r\n ))}\r\n
\r\n );\r\n })}\r\n
\r\n
\r\n )}\r\n
\r\n
\r\n );\r\n}\r\n","let blankImage =\r\n 'data:image/png;base64,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';\r\n\r\nexport default blankImage;\r\n","import React, { useEffect, useState } from 'react';\r\nimport { fabric } from 'fabric';\r\nimport blankCanvas from '../assets/blankCanvas';\r\n\r\nexport function QuiltiCanvas({ color, width, drawMode, background, size, canvasState, setCanvasStateHistory, canvasRef }) {\r\n const [canvas, setCanvas] = useState();\r\n const [eventListenerAttached, setEventListenerAttached] = useState(false);\r\n\r\n useEffect(() => {\r\n setCanvas(\r\n new fabric.Canvas('canvas', {\r\n width: size,\r\n height: size,\r\n backgroundColor: background.color,\r\n isDrawingMode: true,\r\n })\r\n );\r\n }, []);\r\n\r\n useEffect(() => {\r\n if (canvas && !eventListenerAttached) {\r\n canvasRef.current = canvas;\r\n canvas.on('mouse:up', event => {\r\n canvas.renderAll();\r\n // Wait for next tick as the new path the user just draw has not been rendered onto the canvas yet\r\n setTimeout(() => {\r\n let canvasImage = canvas.toDataURL();\r\n let historyItemsToKeep = 128; //equates to about 10mb cap in memory usage\r\n setCanvasStateHistory(canvasStateHistory => [...canvasStateHistory.slice(historyItemsToKeep * -1), canvasImage]);\r\n }, 0);\r\n });\r\n // Assign initial, blank state\r\n setTimeout(() => setCanvasStateHistory([blankCanvas]), 0);\r\n setEventListenerAttached(true);\r\n }\r\n }, [canvas]);\r\n\r\n useEffect(() => {\r\n // If we've been pipped in a new canvasState then apply it\r\n if (canvas && canvasState && canvasState.state) {\r\n fabric.Image.fromURL(canvasState.state, img => {\r\n img.set({ left: 0, top: 0, width: size, height: size });\r\n canvas.add(img);\r\n });\r\n }\r\n }, [canvasState]);\r\n\r\n useEffect(() => {\r\n if (!canvas) return;\r\n\r\n canvas.freeDrawingBrush = new fabric[drawMode + 'Brush'](canvas);\r\n canvas.freeDrawingBrush.color = color;\r\n canvas.freeDrawingBrush.width = width;\r\n canvas.renderAll();\r\n }, [color, width, drawMode, canvas]);\r\n\r\n useEffect(() => {\r\n if (!canvas || !background) return;\r\n\r\n canvas.clear();\r\n canvas.setBackgroundColor(background.color);\r\n setTimeout(() => setCanvasStateHistory([blankCanvas]), 0);\r\n }, [background]);\r\n\r\n return ;\r\n}\r\n","import React, { useEffect, useState } from 'react';\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\r\nimport { faPaintBrush, faSprayCan, faDotCircle } from '@fortawesome/free-solid-svg-icons';\r\nimport { TooltipButton } from './TooltipButton';\r\n\r\nexport function BrushPicker({ drawMode, setDrawMode }) {\r\n return (\r\n
\r\n setDrawMode('Pencil')}\r\n buttonStyle={{ backgroundColor: drawMode === 'Pencil' ? 'lightgray' : '' }}>\r\n \r\n \r\n\r\n setDrawMode('Spray')}\r\n buttonStyle={{ backgroundColor: drawMode === 'Spray' ? 'lightgray' : '' }}>\r\n \r\n \r\n\r\n setDrawMode('Circle')}\r\n buttonStyle={{ backgroundColor: drawMode === 'Circle' ? 'lightgray' : '' }}>\r\n \r\n \r\n
\r\n );\r\n}\r\n","import React, { useEffect, useState } from 'react';\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\r\nimport { faSquare } from '@fortawesome/free-solid-svg-icons';\r\nimport { GithubPicker } from 'react-color';\r\n\r\nexport function ColorPicker({ color, setColor }) {\r\n const [isOpen, setIsOpen] = useState(false);\r\n\r\n let chooseColor = color => {\r\n setIsOpen(false);\r\n setColor(color);\r\n };\r\n\r\n let colors = [\r\n '#2C2C2C',\r\n '#B80000',\r\n '#DB3E00',\r\n '#FCCB00',\r\n '#008B02',\r\n '#006B76',\r\n '#1273DE',\r\n '#004DCF',\r\n '#5300EB',\r\n // Row 2\r\n '#D3D3D3',\r\n '#EB9694',\r\n '#FAD0C3',\r\n '#FEF3BD',\r\n '#C1E1C5',\r\n '#BEDADC',\r\n '#C4DEF6',\r\n '#BED3F3',\r\n '#D4C4FB',\r\n ];\r\n\r\n return (\r\n
\r\n \r\n {isOpen && (\r\n
\r\n chooseColor(colorParam.hex)}\r\n triangle=\"top-left\"\r\n />\r\n
\r\n )}\r\n
\r\n );\r\n}\r\n","import React, { useEffect, useState } from 'react';\r\nimport { Slider } from 'office-ui-fabric-react/lib/Slider';\r\nimport ReactTooltip from 'react-tooltip';\r\n\r\nexport function WidthPicker({ width, setWidth }) {\r\n return (\r\n <>\r\n
\r\n setWidth(widthParam)}\r\n showValue={false}\r\n />\r\n
\r\n \r\n Width ({width - 3})\r\n \r\n \r\n );\r\n}\r\n","import React, { useEffect, useState } from 'react';\r\nimport Dialog from '@material-ui/core/Dialog';\r\nimport DialogActions from '@material-ui/core/DialogActions';\r\nimport DialogContent from '@material-ui/core/DialogContent';\r\nimport DialogContentText from '@material-ui/core/DialogContentText';\r\nimport DialogTitle from '@material-ui/core/DialogTitle';\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\r\nimport { faTrashAlt } from '@fortawesome/free-solid-svg-icons';\r\nimport { TooltipButton } from './TooltipButton';\r\n\r\nexport function ClearButton({ disabled, clear }) {\r\n const [isOpen, setIsOpen] = useState(false);\r\n\r\n let click = () => {\r\n setIsOpen(false);\r\n clear();\r\n };\r\n\r\n return (\r\n
\r\n setIsOpen(true)} disabled={disabled}>\r\n \r\n \r\n setIsOpen(false)}\r\n aria-labelledby=\"alert-dialog-title\"\r\n aria-describedby=\"alert-dialog-description\">\r\n Are you sure you want to clear?\r\n \r\n \r\n Your work of art will be entirely erased, are you sure you want to continue?\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n );\r\n}\r\n","import React, { useEffect, useState } from 'react';\r\nimport Dialog from '@material-ui/core/Dialog';\r\nimport DialogActions from '@material-ui/core/DialogActions';\r\nimport DialogContent from '@material-ui/core/DialogContent';\r\nimport DialogContentText from '@material-ui/core/DialogContentText';\r\nimport DialogTitle from '@material-ui/core/DialogTitle';\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\r\nimport { faSave } from '@fortawesome/free-solid-svg-icons';\r\nimport { TooltipButton } from './TooltipButton';\r\n\r\nexport function DoneButton({ save, disabled }) {\r\n const [isOpen, setIsOpen] = useState(false);\r\n\r\n let clear = () => {\r\n save();\r\n setIsOpen(false);\r\n };\r\n\r\n return (\r\n
\r\n setIsOpen(true)} disabled={disabled}>\r\n \r\n \r\n setIsOpen(false)}\r\n aria-labelledby=\"alert-dialog-title\"\r\n aria-describedby=\"alert-dialog-description\">\r\n Are you all finished?\r\n \r\n \r\n You're about to permanently submit your artwork to the Quilt- Are you all done?\r\n \r\n \r\n Remember to add something near the edges to give your neighboring artists something to work with!\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n );\r\n}\r\n","import React, { useEffect, useState } from 'react';\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\r\nimport { faUndoAlt } from '@fortawesome/free-solid-svg-icons';\r\nimport { TooltipButton } from './TooltipButton';\r\n\r\nexport function UndoButton({ disabled, undo }) {\r\n return (\r\n
\r\n \r\n \r\n \r\n
\r\n );\r\n}\r\n","import React, { useEffect, useRef, useState } from 'react';\r\nimport { NavMenu } from './NavMenu';\r\nimport { QuiltiCanvas } from './QuiltiCanvas';\r\nimport { BrushPicker } from './BrushPicker';\r\nimport { ColorPicker } from './ColorPicker';\r\nimport { NavItem, NavLink } from 'reactstrap';\r\nimport { useParams, useHistory } from 'react-router-dom';\r\nimport { db_init } from '../DB';\r\nimport { util_debugGrid, util_gridInitialize, util_patchCoordinatesFromPatchId, util_gridFirstOrDefault } from '../Utilities';\r\nimport { api_getPatchIdsInRange, api_getPatchDec, api_getPatchImage, api_completePatch } from '../API';\r\nimport { debounce } from 'lodash';\r\nimport { WidthPicker } from './WidthPicker';\r\nimport { ClearButton } from './ClearButton';\r\nimport { DoneButton } from './DoneButton';\r\nimport { UndoButton } from './UndoButton';\r\n\r\nexport function MainDraw() {\r\n const { patchIdParam } = useParams();\r\n const [mainAreaHeight, setMainAreaHeight] = useState(1);\r\n const [mainAreaWidth, setMainAreaWidth] = useState(1);\r\n const [dbIsInitialized, setDbIsInitialized] = useState(false);\r\n const [patchIdsInRange, setPatchIdsInRange] = useState(null);\r\n const [fullGrid, setFullGrid] = useState(null);\r\n const [isLoading, setIsLoading] = useState(true);\r\n const history = useHistory();\r\n const [patchSize, setPatchSize] = useState(null);\r\n // Canvas\r\n const [color, setColor] = useState('#DB3E00');\r\n const [width, setWidth] = useState(null);\r\n const [drawMode, setDrawMode] = useState('Pencil');\r\n const [background, setBackground] = useState({ color: 'lightgray' });\r\n const [canvasState, setCanvasState] = useState({});\r\n const [canvasStateHistory, setCanvasStateHistory] = useState([]);\r\n const canvasRef = useRef();\r\n\r\n //// Init \\\\\\\\\r\n useEffect(() => {\r\n (async () => {\r\n if (!dbIsInitialized) {\r\n db_init();\r\n // only needed because of HMR, if this is a prod build we can pull it out\r\n setDbIsInitialized(true);\r\n }\r\n\r\n setMainAreaHeight(window.innerHeight - document.getElementById('nav').offsetHeight);\r\n setMainAreaWidth(window.innerWidth);\r\n if (window.innerWidth > 500) {\r\n setPatchSize(500);\r\n setWidth(43);\r\n } else {\r\n setPatchSize(300);\r\n setWidth(23);\r\n }\r\n\r\n let pcfp = util_patchCoordinatesFromPatchId(patchIdParam);\r\n setPatchIdsInRange(await api_getPatchIdsInRange(pcfp.x - 1, pcfp.x + 1, pcfp.y + 1, pcfp.y - 1));\r\n })();\r\n }, []);\r\n\r\n // Stage 1-A surroundingPatchesList callback \\\\\r\n useEffect(() => {\r\n if (!patchIdsInRange) return;\r\n (async () => {\r\n let pcfp = util_patchCoordinatesFromPatchId(patchIdParam);\r\n let grid = util_gridInitialize(3, 3, pcfp.x - 1, pcfp.y + 1);\r\n util_debugGrid(grid);\r\n\r\n // Fill in all the ones that we know contain something\r\n await Promise.all(\r\n patchIdsInRange.map(async patchId => {\r\n let patchDecInGridMeta = util_gridFirstOrDefault(grid, p => p.patchId === patchId);\r\n let patchDecFromApi = await api_getPatchDec(patchDecInGridMeta.patch.patchId);\r\n grid[patchDecInGridMeta.columnIndex][patchDecInGridMeta.rowIndex] = patchDecFromApi;\r\n })\r\n );\r\n\r\n // Check if the patch we're supposed to be drawing is already completed (user might have hit back button after submitting)\r\n if (grid[1][1].status === 'ACT') history.replace('/view/' + patchIdParam);\r\n\r\n util_debugGrid(grid);\r\n setFullGrid(grid);\r\n })();\r\n }, [patchIdsInRange]);\r\n\r\n // Stage 2-A fullGrid Callback \\\\\r\n useEffect(() => {\r\n if (!fullGrid) return;\r\n (async () => {\r\n setIsLoading(false);\r\n let result = util_gridFirstOrDefault(fullGrid, patch => patch.status === 'partial');\r\n let patchDecMissingFullImage = result && result.patch;\r\n if (patchDecMissingFullImage) {\r\n let image = await api_getPatchImage(patchDecMissingFullImage.patchId);\r\n patchDecMissingFullImage.src = image;\r\n patchDecMissingFullImage.status = 'full';\r\n setFullGrid([...fullGrid]);\r\n\r\n //util_debugGrid(fullGrid);\r\n }\r\n })();\r\n }, [fullGrid]);\r\n\r\n //// User interaction / onClick bindings \\\\\\\\\r\n let resizeEventDebounced = debounce(() => {\r\n setMainAreaHeight(window.innerHeight - document.getElementById('nav').offsetHeight);\r\n setMainAreaWidth(window.innerWidth);\r\n }, 50);\r\n useEffect(() => {\r\n window.addEventListener('resize', resizeEventDebounced);\r\n return () => {\r\n window.removeEventListener('resize', resizeEventDebounced);\r\n };\r\n }, []);\r\n\r\n let save = async () => {\r\n // Two known library issues here that continue to bite me-\r\n // You cant use the fabric canvas (canvasRef) for toDataUrl to render it as a compressed jpg, it simply doesn't work. The uncompressed png is fine.\r\n // You cant use document.getElementById('canvas') because this will grab a version of the canvas scaled by the window.devicePixelRatio.\r\n // Best solution I have is to construct two custom sized image objects which we then pull into a new canvas and do a toDataUrl on those.\r\n // Canvas is tricky mannnn...\r\n\r\n // Pull in the uncompressed png from canvas, this should be immune to dpi scaling issues\r\n let imageUncompressed = canvasRef.current.toDataURL();\r\n\r\n // Construct a placeholder image\r\n let imageObj = new Image();\r\n imageObj.src = imageUncompressed;\r\n await imageObj.decode();\r\n\r\n // convert out image object into a canvas, and compress it down for the mini image\r\n let miniCanvas = document.createElement('canvas');\r\n let miniCtx = miniCanvas.getContext('2d');\r\n miniCanvas.width = 100;\r\n miniCanvas.height = 100;\r\n miniCtx.drawImage(imageObj, 0, 0, 100, 100);\r\n let imageMini = miniCanvas.toDataURL('image/jpeg', 0.1);\r\n\r\n // Do the same for the medium sized image\r\n let mediumCanvas = document.createElement('canvas');\r\n let mediumCtx = mediumCanvas.getContext('2d');\r\n mediumCanvas.width = patchSize;\r\n mediumCanvas.height = patchSize;\r\n mediumCtx.drawImage(imageObj, 0, 0, patchSize, patchSize);\r\n let image = mediumCanvas.toDataURL('image/jpeg', 0.5);\r\n\r\n // Patch up the Patch\r\n let respPatchId = await api_completePatch(patchIdParam, image, imageMini);\r\n history.push('/view/' + respPatchId);\r\n };\r\n\r\n let undo = () => {\r\n canvasStateHistory.pop();\r\n let [previousState] = canvasStateHistory.slice(-1);\r\n setCanvasStateHistory([...canvasStateHistory]);\r\n setCanvasState({ state: previousState });\r\n };\r\n\r\n let clear = () => {\r\n setBackground(background => ({ ...background }));\r\n };\r\n\r\n //// Dynamic CSS styling / display aids \\\\\\\\\r\n let calculateFullGridClass = (column, row) => {\r\n let ret = '';\r\n switch (column) {\r\n case 0:\r\n ret += 'column-left grid-right-align ';\r\n break;\r\n case 1:\r\n ret += 'column-mid ';\r\n break;\r\n case 2:\r\n ret += 'column-right grid-left-align ';\r\n break;\r\n default:\r\n throw 'bad column in calculateFullGridClass';\r\n }\r\n\r\n switch (row) {\r\n case 0:\r\n ret += 'row-top grid-bottom-align ';\r\n break;\r\n case 1:\r\n ret += 'row-mid ';\r\n break;\r\n case 2:\r\n ret += 'row-bottom grid-top-align ';\r\n break;\r\n default:\r\n throw 'bad row in calculateFullGridClass';\r\n }\r\n\r\n return ret;\r\n };\r\n\r\n let calculateLayoutContainerStyle = () => {\r\n return {\r\n display: 'grid',\r\n gridTemplateColumns: `${patchSize}px ${patchSize}px ${patchSize}px`,\r\n gridTemplateRows: `${patchSize}px ${patchSize}px ${patchSize}px`,\r\n };\r\n };\r\n\r\n return (\r\n
\r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n
\r\n
\r\n
\r\n \r\n \r\n {color && drawMode && width && (\r\n
\r\n \r\n \r\n \r\n
\r\n )}\r\n
\r\n
\r\n
\r\n
\r\n {color && width && drawMode && background && patchSize && (\r\n
\r\n {fullGrid &&\r\n fullGrid.map((column, i) => {\r\n return column.map((patch, j) => {\r\n return i === 1 && j == 1 ? (\r\n // Our canvas\r\n \r\n ) : (\r\n // The 8 surrounding patches\r\n
\r\n \r\n
\r\n );\r\n });\r\n })}\r\n
\r\n )}\r\n
\r\n
\r\n );\r\n}\r\n","import React, { useEffect, useState } from 'react';\r\nimport { NavMenu } from './NavMenu';\r\nimport axios from 'axios';\r\nimport { TextField } from '@material-ui/core';\r\n\r\nexport function MainAdmin() {\r\n const [patchId, setPatchId] = useState('');\r\n const [patchImage, setPatchImage] = useState(null);\r\n const [creatorIp, setCreatorIp] = useState('');\r\n const [reqStatus, setReqStatus] = useState('');\r\n\r\n useEffect(() => {\r\n (async () => {})();\r\n }, []);\r\n\r\n let checkImage = async () => {\r\n setPatchImage(null);\r\n setReqStatus('');\r\n let resp = await axios.get('/api/Patch/' + patchId);\r\n setPatchImage(resp.data.imageMini);\r\n };\r\n\r\n useEffect(() => {\r\n setPatchImage(null);\r\n }, [patchId]);\r\n\r\n let removeImage = async banUser => {\r\n let resp = await axios.delete('/api/Patch/' + patchId + '/' + creatorIp + '/' + banUser);\r\n console.log({ resp });\r\n setReqStatus(resp.status);\r\n };\r\n\r\n let fieldMargin = { marginTop: '3rem' };\r\n\r\n return (\r\n
\r\n \r\n
Because we cant have nice things.
\r\n
\r\n setCreatorIp(e.target.value)} />\r\n setPatchId(e.target.value)} />\r\n
\r\n
\r\n \r\n {patchImage && }\r\n
\r\n
\r\n \r\n
\r\n
\r\n \r\n
\r\n
{reqStatus}
\r\n
\r\n );\r\n}\r\n","import React, { useEffect, useState } from 'react';\r\nimport Dialog from '@material-ui/core/Dialog';\r\nimport DialogActions from '@material-ui/core/DialogActions';\r\nimport DialogContent from '@material-ui/core/DialogContent';\r\nimport DialogContentText from '@material-ui/core/DialogContentText';\r\nimport DialogTitle from '@material-ui/core/DialogTitle';\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\r\nimport { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';\r\n\r\nexport default function GlobalErrorDialog() {\r\n const [errorCode, setErrorCode] = useState(null);\r\n const [isOpen, setIsOpen] = useState(false);\r\n\r\n const errorText = {\r\n 403: 'We only allow you to create a limited number of Patches per hour. Try again later!',\r\n 404: \"Oops, we couldn't find that Patch right now. You might have timed out- you must finish your patch within 1 hour.\",\r\n 409: 'Oops, someone else is working on that patch right now. Try another one.',\r\n };\r\n\r\n useEffect(() => {\r\n window.QuiltiError = code => {\r\n setErrorCode(code);\r\n };\r\n }, []);\r\n\r\n useEffect(() => {\r\n if (errorCode) setIsOpen(true);\r\n }, [errorCode]);\r\n useEffect(() => {\r\n if (isOpen === false) setErrorCode(null);\r\n }, [isOpen]);\r\n\r\n return (\r\n setIsOpen(false)}\r\n aria-labelledby=\"alert-dialog-title\"\r\n aria-describedby=\"alert-dialog-description\">\r\n \r\n \r\n Something went wrong..\r\n \r\n \r\n \r\n {errorText[errorCode] || 'An unknown error occurred. Please refresh and try again.'}\r\n \r\n \r\n \r\n \r\n \r\n \r\n );\r\n}\r\n","import React, { useEffect, useState } from 'react';\r\nimport Dialog from '@material-ui/core/Dialog';\r\nimport DialogActions from '@material-ui/core/DialogActions';\r\nimport DialogContent from '@material-ui/core/DialogContent';\r\nimport DialogContentText from '@material-ui/core/DialogContentText';\r\nimport DialogTitle from '@material-ui/core/DialogTitle';\r\n\r\nexport default function GeneralDialog() {\r\n const [isOpen, setIsOpen] = useState(false);\r\n const [title, setTitle] = useState();\r\n const [message, setMessage] = useState();\r\n\r\n useEffect(() => {\r\n window.QuiltiDialog = (title, message) => {\r\n setTitle(title);\r\n setMessage(message);\r\n };\r\n }, []);\r\n\r\n useEffect(() => {\r\n if (title && message) setIsOpen(true);\r\n }, [title, message]);\r\n\r\n let onClose = () => {\r\n setIsOpen(false);\r\n setMessage('');\r\n setTitle('');\r\n };\r\n\r\n return (\r\n \r\n {title}\r\n \r\n {message}\r\n \r\n \r\n \r\n \r\n \r\n );\r\n}\r\n","import React, { useEffect } from 'react';\r\nimport { Route } from 'react-router';\r\nimport { Layout } from './components/Layout';\r\nimport { MainView } from './components/MainView';\r\nimport { MainDraw } from './components/MainDraw';\r\nimport { MainAdmin } from './components/MainAdmin';\r\n\r\nimport GlobalErrorDialog from './components/GlobalErrorDialog';\r\nimport GeneralDialog from './components/GeneralDialog';\r\n\r\nimport './custom.css';\r\nimport './components/Global.css';\r\n\r\nexport default function App() {\r\n useEffect(() => {\r\n let displayedGreeting = localStorage.getItem('displayedGreeting');\r\n if (!displayedGreeting && window.QuiltiDialog) {\r\n window.QuiltiDialog(\r\n 'Welcome!',\r\n 'Welcome to Quilti! Navigate around using the arrow buttons on the edge of the quilt and click on an empty space to add your artwork there!'\r\n );\r\n localStorage.setItem('displayedGreeting', true);\r\n }\r\n }, []);\r\n\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n );\r\n}\r\n","// In production, we register a service worker to serve assets from local cache.\r\n\r\n// This lets the app load faster on subsequent visits in production, and gives\r\n// it offline capabilities. However, it also means that developers (and users)\r\n// will only see deployed updates on the \"N+1\" visit to a page, since previously\r\n// cached resources are updated in the background.\r\n\r\n// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.\r\n// This link also includes instructions on opting out of this behavior.\r\n\r\nconst isLocalhost = Boolean(\r\n window.location.hostname === 'localhost' ||\r\n // [::1] is the IPv6 localhost address.\r\n window.location.hostname === '[::1]' ||\r\n // 127.0.0.1/8 is considered localhost for IPv4.\r\n window.location.hostname.match(\r\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\r\n )\r\n);\r\n\r\nexport default function register () {\r\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\r\n // The URL constructor is available in all browsers that support SW.\r\n const publicUrl = new URL(process.env.PUBLIC_URL, window.location);\r\n if (publicUrl.origin !== window.location.origin) {\r\n // Our service worker won't work if PUBLIC_URL is on a different origin\r\n // from what our page is served on. This might happen if a CDN is used to\r\n // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374\r\n return;\r\n }\r\n\r\n window.addEventListener('load', () => {\r\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\r\n\r\n if (isLocalhost) {\r\n // This is running on localhost. Lets check if a service worker still exists or not.\r\n checkValidServiceWorker(swUrl);\r\n } else {\r\n // Is not local host. Just register service worker\r\n registerValidSW(swUrl);\r\n }\r\n });\r\n }\r\n}\r\n\r\nfunction registerValidSW (swUrl) {\r\n navigator.serviceWorker\r\n .register(swUrl)\r\n .then(registration => {\r\n registration.onupdatefound = () => {\r\n const installingWorker = registration.installing;\r\n installingWorker.onstatechange = () => {\r\n if (installingWorker.state === 'installed') {\r\n if (navigator.serviceWorker.controller) {\r\n // At this point, the old content will have been purged and\r\n // the fresh content will have been added to the cache.\r\n // It's the perfect time to display a \"New content is\r\n // available; please refresh.\" message in your web app.\r\n console.log('New content is available; please refresh.');\r\n } else {\r\n // At this point, everything has been precached.\r\n // It's the perfect time to display a\r\n // \"Content is cached for offline use.\" message.\r\n console.log('Content is cached for offline use.');\r\n }\r\n }\r\n };\r\n };\r\n })\r\n .catch(error => {\r\n console.error('Error during service worker registration:', error);\r\n });\r\n}\r\n\r\nfunction checkValidServiceWorker (swUrl) {\r\n // Check if the service worker can be found. If it can't reload the page.\r\n fetch(swUrl)\r\n .then(response => {\r\n // Ensure service worker exists, and that we really are getting a JS file.\r\n if (\r\n response.status === 404 ||\r\n response.headers.get('content-type').indexOf('javascript') === -1\r\n ) {\r\n // No service worker found. Probably a different app. Reload the page.\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister().then(() => {\r\n window.location.reload();\r\n });\r\n });\r\n } else {\r\n // Service worker found. Proceed as normal.\r\n registerValidSW(swUrl);\r\n }\r\n })\r\n .catch(() => {\r\n console.log(\r\n 'No internet connection found. App is running in offline mode.'\r\n );\r\n });\r\n}\r\n\r\nexport function unregister () {\r\n if ('serviceWorker' in navigator) {\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister();\r\n });\r\n }\r\n}\r\n","import 'bootstrap/dist/css/bootstrap.css';\r\nimport React from 'react';\r\nimport ReactDOM from 'react-dom';\r\nimport { BrowserRouter } from 'react-router-dom';\r\nimport App from './App';\r\nimport registerServiceWorker from './registerServiceWorker';\r\n\r\nconst baseUrl = document.getElementsByTagName('base')[0].getAttribute('href');\r\nconst rootElement = document.getElementById('root');\r\n\r\nReactDOM.render(\r\n \r\n \r\n ,\r\n rootElement);\r\n\r\nregisterServiceWorker();\r\n\r\n"],"sourceRoot":""}