From f56d7759b4e75ed7104096bfc108b269d603ec89 Mon Sep 17 00:00:00 2001 From: ahmedmgamal94 <98055904+ahmedmgamal94@users.noreply.github.com> Date: Thu, 29 Aug 2024 21:06:27 -0700 Subject: [PATCH 1/2] ncrypt and parse loadout from store --- index.html | 4 +- package-lock.json | 128 ++++++++ package.json | 3 + .../armor/components/ArmorCustomization.tsx | 2 + .../loadouts/components/ShareLoadout.tsx | 276 ++++++++++++++++++ .../components/manualTestParseLoadoutLink.ts | 42 +++ .../loadouts/components/parseLoadoutLink.ts | 18 ++ 7 files changed, 471 insertions(+), 2 deletions(-) create mode 100644 src/features/loadouts/components/ShareLoadout.tsx create mode 100644 src/features/loadouts/components/manualTestParseLoadoutLink.ts create mode 100644 src/features/loadouts/components/parseLoadoutLink.ts diff --git a/index.html b/index.html index 891a938..d8c4fb6 100644 --- a/index.html +++ b/index.html @@ -2,9 +2,9 @@ - + - Vite + React + D2Loadouts
diff --git a/package-lock.json b/package-lock.json index 25e83dd..44d50c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "@mui/system": "^5.15.20", "@reduxjs/toolkit": "^2.2.6", "@tanstack/react-table": "^8.17.3", + "@types/react-beautiful-dnd": "^13.1.8", "@types/react-slick": "^0.23.13", "axios": "^1.7.2", "dexie": "^4.0.8", @@ -22,7 +23,9 @@ "dotenv": "^16.4.5", "framer-motion": "^11.3.29", "heap-js": "^2.5.0", + "lz-string": "^1.5.0", "react": "^18.2.0", + "react-beautiful-dnd": "^13.1.1", "react-dom": "^18.2.0", "react-redux": "^9.1.2", "react-router-dom": "^6.23.1", @@ -4796,6 +4799,15 @@ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", + "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -4856,6 +4868,14 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-beautiful-dnd": { + "version": "13.1.8", + "resolved": "https://registry.npmjs.org/@types/react-beautiful-dnd/-/react-beautiful-dnd-13.1.8.tgz", + "integrity": "sha512-E3TyFsro9pQuK4r8S/OL6G99eq7p8v29sX0PM7oT8Z+PJfZvSQTx4zTQbUJ+QZXioAF0e7TGBEcA1XhYhCweyQ==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-dom": { "version": "18.3.0", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", @@ -4874,6 +4894,25 @@ "@types/react": "*" } }, + "node_modules/@types/react-redux": { + "version": "7.1.33", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.33.tgz", + "integrity": "sha512-NF8m5AjWCkert+fosDsN3hAlHzpjSiXlVy9EgQEmLoBhaNXbmyeGs/aj5dQzKuF+/q+S7JQagorGDW8pJ28Hmg==", + "dependencies": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, + "node_modules/@types/react-redux/node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, "node_modules/@types/react-slick": { "version": "0.23.13", "resolved": "https://registry.npmjs.org/@types/react-slick/-/react-slick-0.23.13.tgz", @@ -5968,6 +6007,14 @@ "node": ">= 8" } }, + "node_modules/css-box-model": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz", + "integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==", + "dependencies": { + "tiny-invariant": "^1.0.6" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -9183,6 +9230,14 @@ "yallist": "^3.0.2" } }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "bin": { + "lz-string": "bin/bin.js" + } + }, "node_modules/make-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", @@ -10746,6 +10801,11 @@ } ] }, + "node_modules/raf-schd": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", + "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==" + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -10766,6 +10826,61 @@ "node": ">=0.10.0" } }, + "node_modules/react-beautiful-dnd": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.1.tgz", + "integrity": "sha512-0Lvs4tq2VcrEjEgDXHjT98r+63drkKEgqyxdA7qD3mvKwga6a5SscbdLPO2IExotU1jW8L0Ksdl0Cj2AF67nPQ==", + "dependencies": { + "@babel/runtime": "^7.9.2", + "css-box-model": "^1.2.0", + "memoize-one": "^5.1.1", + "raf-schd": "^4.0.2", + "react-redux": "^7.2.0", + "redux": "^4.0.4", + "use-memo-one": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8.5 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.5 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-beautiful-dnd/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "node_modules/react-beautiful-dnd/node_modules/react-redux": { + "version": "7.2.9", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", + "integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==", + "dependencies": { + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^17.0.2" + }, + "peerDependencies": { + "react": "^16.8.3 || ^17 || ^18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/react-beautiful-dnd/node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, "node_modules/react-devtools-core": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-5.3.1.tgz", @@ -12233,6 +12348,11 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -12511,6 +12631,14 @@ "punycode": "^2.1.0" } }, + "node_modules/use-memo-one": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz", + "integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/use-scramble": { "version": "2.2.15", "resolved": "https://registry.npmjs.org/use-scramble/-/use-scramble-2.2.15.tgz", diff --git a/package.json b/package.json index d506eb4..8899bdf 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@mui/system": "^5.15.20", "@reduxjs/toolkit": "^2.2.6", "@tanstack/react-table": "^8.17.3", + "@types/react-beautiful-dnd": "^13.1.8", "@types/react-slick": "^0.23.13", "axios": "^1.7.2", "dexie": "^4.0.8", @@ -24,7 +25,9 @@ "dotenv": "^16.4.5", "framer-motion": "^11.3.29", "heap-js": "^2.5.0", + "lz-string": "^1.5.0", "react": "^18.2.0", + "react-beautiful-dnd": "^13.1.1", "react-dom": "^18.2.0", "react-redux": "^9.1.2", "react-router-dom": "^6.23.1", diff --git a/src/features/armor/components/ArmorCustomization.tsx b/src/features/armor/components/ArmorCustomization.tsx index d416c0e..59231f9 100644 --- a/src/features/armor/components/ArmorCustomization.tsx +++ b/src/features/armor/components/ArmorCustomization.tsx @@ -6,6 +6,7 @@ import { ManifestSubclass } from '../../../types/manifest-types'; import AbilitiesModification from '../../subclass/AbilitiesModification'; import { Button, Box } from '@mui/material'; import { styled } from '@mui/material/styles'; +import ShareLoadout from '../../loadouts/components/ShareLoadout'; interface ArmorCustomizationProps { onBackClick: () => void; @@ -43,6 +44,7 @@ const ArmorCustomization: React.FC = ({
+ {/* Add the ShareLoadout component here */}
diff --git a/src/features/loadouts/components/ShareLoadout.tsx b/src/features/loadouts/components/ShareLoadout.tsx new file mode 100644 index 0000000..6c5c00b --- /dev/null +++ b/src/features/loadouts/components/ShareLoadout.tsx @@ -0,0 +1,276 @@ +import React, { useState } from 'react'; +import { useSelector } from 'react-redux'; +import { RootState } from '../../../store/index'; +import { compressToEncodedURIComponent, decompressFromEncodedURIComponent } from 'lz-string'; +import { + Button, + TextField, + Box, + List, + ListItem, + ListItemIcon, + ListItemText, + Dialog, + DialogTitle, + DialogContent, + DialogActions, + IconButton, +} from '@mui/material'; +import CloseIcon from '@mui/icons-material/Close'; +import { styled } from '@mui/material/styles'; +import { DragDropContext, Droppable, Draggable, DropResult } from 'react-beautiful-dnd'; + +const StyledDialog = styled(Dialog)(({ theme }) => ({ + '& .MuiDialog-paper': { + backgroundColor: 'rgba(0, 0, 0, 0.5)', + backdropFilter: 'blur(10px)', + color: 'white', + fontFamily: 'Helvetica, Arial, sans-serif', + borderRadius: 0, + }, +})); + +const TransparentButton = styled(Button)(({ theme }) => ({ + background: 'transparent', + color: 'white', + padding: theme.spacing(1, 2), + fontFamily: 'Helvetica, Arial, sans-serif', + '&:hover': { + background: 'rgba(255, 255, 255, 0.1)', + }, + borderRadius: 0, + border: '1px solid white', +})); + +const StyledTextField = styled(TextField)(({ theme }) => ({ + '& .MuiOutlinedInput-root': { + color: 'white', + fontFamily: 'Helvetica, Arial, sans-serif', + '& fieldset': { + borderColor: 'white', + borderRadius: 0, + }, + '&:hover fieldset': { + borderColor: 'white', + }, + '&.Mui-focused fieldset': { + borderColor: 'white', + }, + }, + '& .MuiInputLabel-root': { + color: 'white', + fontFamily: 'Helvetica, Arial, sans-serif', + }, +})); + +const StatIcon = styled('img')({ + width: 24, + height: 24, + marginRight: 10, +}); + +const StyledList = styled(List)({ + width: '100%', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', +}); + +const StyledListItem = styled(ListItem)({ + backgroundColor: 'rgba(255, 255, 255, 0.1)', + marginBottom: '4px', + width: '200px', + padding: '4px 8px', + borderRadius: 0, + border: '1px solid white', + '&:hover': { + backgroundColor: 'rgba(255, 255, 255, 0.2)', + }, +}); + +const statIcons: Record = { + mobility: + 'https://www.bungie.net/common/destiny2_content/icons/e26e0e93a9daf4fdd21bf64eb9246340.png', + resilience: + 'https://www.bungie.net/common/destiny2_content/icons/202ecc1c6febeb6b97dafc856e863140.png', + recovery: + 'https://www.bungie.net/common/destiny2_content/icons/128eee4ee7fc127851ab32eac6ca91cf.png', + discipline: + 'https://www.bungie.net/common/destiny2_content/icons/79be2d4adef6a19203f7385e5c63b45b.png', + intellect: + 'https://www.bungie.net/common/destiny2_content/icons/d1c154469670e9a592c9d4cbdcae5764.png', + strength: + 'https://www.bungie.net/common/destiny2_content/icons/ea5af04ccd6a3470a44fd7bb0f66e2f7.png', +}; + +const ShareLoadout: React.FC = () => { + const [open, setOpen] = useState(false); + const [shareLink, setShareLink] = useState(''); + const [parsedLink, setParsedLink] = useState(''); + const loadoutState = useSelector((state: RootState) => ({ + helmetMods: state.loadoutConfig.loadout.helmetMods, + gauntletMods: state.loadoutConfig.loadout.gauntletMods, + chestArmorMods: state.loadoutConfig.loadout.chestArmorMods, + legArmorMods: state.loadoutConfig.loadout.legArmorMods, + subclassConfig: state.loadoutConfig.loadout.subclassConfig, + selectedValues: state.dashboard.selectedValues, + selectedExoticItemHash: state.dashboard.selectedExoticItemHash, + })); + + const [statPriority, setStatPriority] = useState([ + 'mobility', + 'resilience', + 'recovery', + 'discipline', + 'intellect', + 'strength', + ]); + + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); + + const onDragEnd = (result: DropResult) => { + if (!result.destination) return; + + const items = Array.from(statPriority); + const [reorderedItem] = items.splice(result.source.index, 1); + items.splice(result.destination.index, 0, reorderedItem); + + setStatPriority(items); + }; + + const generateShareLink = () => { + const dataToShare = { + ...loadoutState, + statPriority, + }; + const compressedData = compressToEncodedURIComponent(JSON.stringify(dataToShare)); + const shareableLink = `${window.location.origin}/loadout?data=${compressedData}`; + setShareLink(shareableLink); + }; + + const parseLink = () => { + try { + const url = new URL(shareLink); + const compressedData = url.searchParams.get('data'); + if (!compressedData) { + throw new Error('Invalid loadout link'); + } + const decompressedData = decompressFromEncodedURIComponent(compressedData); + if (!decompressedData) { + throw new Error('Failed to decompress loadout data'); + } + const parsedData = JSON.parse(decompressedData); + setParsedLink(JSON.stringify(parsedData, null, 2)); + console.log('Parsed loadout:', parsedData); + } catch (error) { + console.error('Error parsing loadout link:', error); + setParsedLink('Error parsing link'); + } + }; + + const copyToClipboard = () => { + navigator.clipboard.writeText(shareLink).then(() => { + alert('Link copied to clipboard!'); + }); + }; + + return ( + <> + Share Loadout + + + Share Loadout + + + + + + +

Prioritize Stats : drag and drop stats based on which stat matters the most

+ + + {(provided) => ( + + {statPriority.map((stat, index) => ( + + {(provided, snapshot) => ( + + + + + + + )} + + ))} + {provided.placeholder} + + )} + + +
+ + Generate Share Link + + {shareLink && ( + + + + + Copy Link + + Parse Link + + + )} + {parsedLink && ( + + + + )} +
+ + Close + +
+ + ); +}; + +export default ShareLoadout; diff --git a/src/features/loadouts/components/manualTestParseLoadoutLink.ts b/src/features/loadouts/components/manualTestParseLoadoutLink.ts new file mode 100644 index 0000000..8e0518a --- /dev/null +++ b/src/features/loadouts/components/manualTestParseLoadoutLink.ts @@ -0,0 +1,42 @@ +import { decompressFromEncodedURIComponent } from 'lz-string'; + +// The parseLoadoutLink function +const parseLoadoutLink = (link: string) => { + const url = new URL(link); + const compressedData = url.searchParams.get('data'); + + if (!compressedData) { + throw new Error('Invalid loadout link'); + } + + const decompressedData = decompressFromEncodedURIComponent(compressedData); + + if (!decompressedData) { + throw new Error('Failed to decompress loadout data'); + } + + return JSON.parse(decompressedData); +}; + +// Function to test parseLoadoutLink with a manually provided hash +function testWithManualHash(hash: string) { + // Construct the full URL with the provided hash + const fullUrl = `http://example.com/loadout?data=${hash}`; + + console.log('Testing with URL:', fullUrl); + + try { + // Attempt to parse the loadout link + const parsedLoadout = parseLoadoutLink(fullUrl); + console.log('Successfully parsed loadout:'); + console.log(JSON.stringify(parsedLoadout, null, 2)); // Pretty print the result + } catch (error) { + console.error('Error parsing loadout link:', error); + } +} + +// REPLACE THIS WITH YOUR ACTUAL GENERATED HASH +const manuallyProvidedHash = 'https://localhost:5173/loadout?data=N4IgFgpgNgthAuBZA9gEwM4gFwG1QEt4IYAJAQ3TGwEYBOADgAYA2a+gVnoHYAaEABwgAnANYA5MnGwgQfQaIAiEdAGMh+fvHzIAdtNkDhIgJIrd+virJEA5siEBPbACYALN3rOuAZnbs++OgA8gDuOhCo2PBCAK4QfDqSENIAojCaDgAEKKiZAMrIKiIIBvhmeljg8PD86FgA9PUARjE6NvgQAHTh8PVmMDC69ajKWjoOzgD65UQ6vWW66PVMqM4Q1GTOZFzMAGYjm1zszk0QTdSu1Iz0rqgqu-SdAFb8NgYQ4UI2DgDCyOjwbCMSzIKBQCAqLRNcHkSjYAC01AAvjwCERSBQqFgrlwmEwdv5DKIJFJKgZ5CIlKp1JptBUZHIjKZzGTLNYIHZHC5aNRnNQuFdGN4AsEwhEorF4iBEqSQGkMtk0PlCsVAQFytIwNVag1mq12l0en1kAMhiMAfhxlMZh95uUluwyA8jvRmCpaM4VMwfGRtvRfK5vKh6PtnMH9s9Xu9Pt8-gCgSCwRCoTDMQjkaiQIRiLCsTi8YwCYziUkLETKco1BotCyGeXmfSDFZbPYnFhnDy+QLGEKRaFwpEsNE4glS5V5fAsjllUUSura1qanVGi02h1ughjaadMNRpaJtNdLM7Yt6o7nZw3R6vT6-QGgyHVuHUJG3nwPsJY-9AVhgSAzEmkL4NCEC5umKJojmabYoWBZFuWJLJKy5ZUlWtK1uSTIashzYcq23K8vygrClmooDhKI7SmOcrpJOiq5AUs5qlm2FVEuuqrgaG69P0gw7uaYwHjacz1AsOgOk63CXu6nret4vq4vez5ho+r7Rp+vzfgm-6guCQEgWBWCIhBWbooZlw+B6gbOCRFKIWWFKoTSNaNsWJisU27Kcm23hcD4-LeIwHZ9mKg7DlKMpITRCrToxqqlKxi46iu+rrkavFmnuVqHnMtqifa9TOIw1DeN4+zMGQjCoLsFVNL6FxNKc7CNd46wMOwzCdPwbTqV8mnxr+iZ6SmoHQcZAC6fA2GQrTwOCSBoJguCQRicLYgwLBsJwvAIdRmGKJWzl0g5WEYWyLZcu27i4l4viEoE-bikOkqjrKE5TkqcVzixC7asueproam4ZfxWVCUeeViUsKxrBsWw7PsECHMcpznJc1y3PcjwvG+IAfn1cY-n+AHDcBqZrcZmbZqtWLeJ4xWuFwjO0G59nIY5h3Vsd7Ona5-5efh7adkRPYkQ9oUURF1HvfRM7xfO9JJf9IQq50nFpcDJp8buFrZcJJ7ifUtC7F29BMCo3hNIw9xkN4KjnFwZAqK4Hq0GQtC0Os2NRu+Mb9UTQ3JmTo0UxmK2GXTRUXEzXAs7tsr7RW1Jc2d9YeedeGXR2hHdr2pGPWFL1UW9tEfQxKrfWJmp-bqKshGrqVAzxWuZbr4O5SJUNGyb-Jm9blvW7stv2-yTsux27ue2wam+xphPaSTQcGWNYemVBa2RwzMdx3Ze1uU5Kd8xSDZlrh3kEV2xEheRz2UZFqSl7LX3MVXlRK7Xqvq03W7awJ+7WhDTuBVjam3NgPG2dsHZj1dpPL2M88Z+3noNHSgERqGUpuHaCFlvBWW8DZVme8UKc3QkfXmp8BaXV8v5HwQU47ixvuFV6UUZaxQri-RKNcUqA24j-VugkAEdwNksKOpVyqVWqrVeqrhGoQGak0VqdAOCdW6rjfGX4BrE10kvcmWIJqWEgACAAgkIQYQgchLTwGvGmNANqsA4NwAhCd97EJcidUQJ8cIULbG4Dwt0-DXyeow4uzDH6sKYglX67EuFcXSi3UGbcBHHnyqeGG6xNjbD2AcLwKMzgXCuDcO4Dx4FqP9gvLR+kdHgSpmZaCbAhSBncL4RxUVE4HxIW49yqcz6C2zpfUWATC532lqEz6bCImK04fUOuDduGxO3DrfhOUkld2YKsm4NVgzUFkVwM4bovSMF2O6XYTQOrUGYPQdYxTEFaWQYvCpIddGr2poZOp3gGn+kJLvJxRDk7tJ5u49O-MLreOFrnMWZFAlF3vuOEZ5dwkK2rlEqZn9G48JBgs-+SzIYFVWec1wGz6BbPYDspoezmAHKOSc1g5zLk416uogOKDSbL1DiZZ5tSmBvLeR85pHS2muP+Z0vm3Ss6gqvvnCWt8pYlxiqM+FP0JlIumV-NFcSMV60AUI+ouL1nME2ds3ZKh9mHONlSs5FzqBXLnjczRqDg7oKeTUta2DcH4Pji05xvyBV1mPoCkVPk-LeACrQgZksmEP1lXC+WCrEXJQBjEzW8y-4asEckw2IiyqoAqlVGqZA6pkAak1FqbUlFdR6rPAmNrA73IdUiSaIBwQ2GMaY8x2BLHsrWooza9idpfI9T8tC3rE4eLrP6lw11PA+H8RKhhULhmRrlpXDhSKVVzN-mDRJ2KUlVVhukhGWSjgnFyejApWMrWVo0dWtBK82VOqxM4ZwzAGDeHOdQagvLBX8u5j6shnjgUXxFnnehkKhkyromE6Nr82JxuVaitdfDMX6zTUsHkxLvSNWoLsHB5xVnXAFJZdgtxyUHJfeehlZS7Ussebe9e97H3Ptfe+91fKXHfuHX6rxAGwWhqleGmFC7n7jNjcrFFszE3roSVioBp5UM7C4BhrDtAcPku4AFWghGs09iw51OlFbyO3PKde1l1TaMuHo-6RjH6f0HS9WxtyI7PL-qFjncVwHBnSpCQJsZCK36TNg2J5uSaN1Sa1bJ9D5xFPKbw2pjTxHtNkdKQZyjlSjKOtM1gF1bg8G2SMGzazSdB12bTl0zjWAqFBpocFGdIGPMRvA3KyDy642rvEwhlNyyCoZrETmyRBbpFFvkSWjqZbVHXMvUy7RDzwL1vQDEJoKgoAUHQH8HQux8BvCwKAWb83FvoCWgQcS8AyA6BUBAYwg46zUggB8SgyAfx1lQJIMgNgIAABUHCCG0m57AQ8oDoClAtpbZYO1Yj-NCusUGQAohAI9mAz23sfaQkx2b8hsCgD7Sx2zqdfUlac3+b7WBfv-YCHe7S4OhNkmhxQQQkILGgBKT8Mg-AnaEDbH+DHn7WPY9-aO0r+OIWDiJ1KEHZPCGQ5MgzpnLPJzaQ5-lr93OAW48zmznjQuSfpbB2Ljyda+C7CEM9uAcw6cgEGE0fAUBWc5G0kIZQFuOgnYgNb5BtuzAADdhAOGd3+VAgQVAaEt+Eb3ARcqoODyAAEtu2jwDAOHuXrSuekKV8KvnauyB-eF6T5B5OfMyBMmb+3k5w+2-QPbj4p3i8QmQB7xw4ffeqAD5aJ3aAvuh+GuHyPHwbAx7j7lwhHMsdJ6FeQvHaeM8a+sdn7XGF8-IHN5bovLeXd28t+X5vg4-yu+r57uvfvG9B6X-jtvyYO-RC7z3w-VmE+D46Q5jO59kEE-V1YwyWvvni8zAXhfXvL8gBL2Xx3Svd3HfX-evf3fgQPdfVvIgMPX-TvaPWPX-ePT1QrRXYfP9FXL7AXH7dPYnF-aCN-ftD-UAL-K3X-f-VfQA8gqvGvH-DfPgMA-fKAx-Y-SEU-KPbvRA+g5jTnG-QVO-IFTAx-bAwnXAzPTXPjCHHXetQHPbQxefVnbAHQGIMEPgOAcECAeQwvNsZQ1Q03bfI3eALQ7-JQlQqAKaKPMgEYUwsEaHf7YaCIAANXTziH2z-xXwd1OxoB7D4C31oO8J9z3wgKbwCJDxgOGmwECj4HgM4JcD-FIJl3bEYDsOgGTAiBSAAA87syhjAs9dCoAkQgA'; + +// Run the test with the manually provided hash +testWithManualHash(manuallyProvidedHash); \ No newline at end of file diff --git a/src/features/loadouts/components/parseLoadoutLink.ts b/src/features/loadouts/components/parseLoadoutLink.ts new file mode 100644 index 0000000..f48f292 --- /dev/null +++ b/src/features/loadouts/components/parseLoadoutLink.ts @@ -0,0 +1,18 @@ +import { decompressFromEncodedURIComponent } from 'lz-string'; + +export const parseLoadoutLink = (link: string) => { + const url = new URL(link); + const compressedData = url.searchParams.get('data'); + + if (!compressedData) { + throw new Error('Invalid loadout link'); + } + + const decompressedData = decompressFromEncodedURIComponent(compressedData); + + if (!decompressedData) { + throw new Error('Failed to decompress loadout data'); + } + + return JSON.parse(decompressedData); +}; \ No newline at end of file From b964030ce8ddc2b29eef6ae394e62919cb832437 Mon Sep 17 00:00:00 2001 From: ahmedmgamal94 <98055904+ahmedmgamal94@users.noreply.github.com> Date: Fri, 30 Aug 2024 12:03:09 -0700 Subject: [PATCH 2/2] readjusted format --- src/components/LoadoutCustomization.tsx | 3 +- .../armor/components/ArmorCustomization.tsx | 54 ------------------- 2 files changed, 2 insertions(+), 55 deletions(-) delete mode 100644 src/features/armor/components/ArmorCustomization.tsx diff --git a/src/components/LoadoutCustomization.tsx b/src/components/LoadoutCustomization.tsx index 24fac35..364bd12 100644 --- a/src/components/LoadoutCustomization.tsx +++ b/src/components/LoadoutCustomization.tsx @@ -6,6 +6,7 @@ import ModCustomization from '../features/armor/components/ModCustomization'; import EquipLoadout from '../features/loadouts/components/EquipLoadout'; import AbilitiesModification from '../features/subclass/AbilitiesModification'; import { ManifestSubclass } from '../types/manifest-types'; +import ShareLoadout from '../features/loadouts/components/ShareLoadout'; interface LoadoutCustomizationProps { onBackClick: () => void; @@ -71,7 +72,7 @@ const LoadoutCustomization: React.FC = ({ - SHARE LOADOUT BUTTON ? + diff --git a/src/features/armor/components/ArmorCustomization.tsx b/src/features/armor/components/ArmorCustomization.tsx deleted file mode 100644 index 59231f9..0000000 --- a/src/features/armor/components/ArmorCustomization.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React from 'react'; -import './ArmorCustomization.css'; -import LoadoutArmor from './LoadoutArmor'; -import EquipLoadout from '../../loadouts/components/EquipLoadout'; -import { ManifestSubclass } from '../../../types/manifest-types'; -import AbilitiesModification from '../../subclass/AbilitiesModification'; -import { Button, Box } from '@mui/material'; -import { styled } from '@mui/material/styles'; -import ShareLoadout from '../../loadouts/components/ShareLoadout'; - -interface ArmorCustomizationProps { - onBackClick: () => void; - screenshot: string; - subclass: ManifestSubclass; -} - -const TransparentButton = styled(Button)(({ theme }) => ({ - background: 'transparent', - color: 'white', - padding: theme.spacing(1, 2), - '&:hover': { - background: 'rgba(255, 255, 255, 0.1)', - }, - '& .MuiButton-startIcon': { - marginRight: theme.spacing(1), - }, -})); - -const ArmorCustomization: React.FC = ({ - onBackClick, - screenshot, - subclass, -}) => { - return ( -
- - ←} - > - Back - - -
- - - {/* Add the ShareLoadout component here */} -
- -
- ); -}; - -export default ArmorCustomization;