diff --git a/package-lock.json b/package-lock.json index f429212..8dd5bcb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -76,6 +76,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/generator": "^7.28.6", @@ -479,7 +480,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" @@ -496,7 +496,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -512,7 +511,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -528,7 +526,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", @@ -546,7 +543,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.6.tgz", "integrity": "sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", "@babel/traverse": "^7.28.6" @@ -647,7 +643,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "license": "MIT", - "peer": true, "engines": { "node": ">=6.9.0" }, @@ -768,7 +763,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.28.6.tgz", "integrity": "sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, @@ -955,7 +949,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -1021,7 +1014,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1068,7 +1060,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz", "integrity": "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6" @@ -1137,7 +1128,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.28.6.tgz", "integrity": "sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.28.6" @@ -1154,7 +1144,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1170,7 +1159,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.28.6.tgz", "integrity": "sha512-5suVoXjC14lUN6ZL9OLKIHCNVWCrqGqlmEp/ixdXjvgnEl/kauLvvMO/Xw9NyMc95Joj1AeLVPVMvibBgSoFlA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.28.6" @@ -1187,7 +1175,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1203,7 +1190,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.6.tgz", "integrity": "sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", "@babel/plugin-transform-destructuring": "^7.28.5" @@ -1220,7 +1206,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.6.tgz", "integrity": "sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, @@ -1300,7 +1285,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.28.6.tgz", "integrity": "sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, @@ -1346,7 +1330,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1362,7 +1345,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" @@ -1395,7 +1377,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-module-transforms": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1", @@ -1414,7 +1395,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" @@ -1447,7 +1427,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1512,7 +1491,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1" @@ -1608,7 +1586,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1734,7 +1711,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.28.6.tgz", "integrity": "sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.28.6" @@ -1751,7 +1727,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1848,7 +1823,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1883,7 +1857,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1899,7 +1872,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.28.6.tgz", "integrity": "sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.28.6" @@ -1932,7 +1904,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.28.6.tgz", "integrity": "sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.28.6" @@ -2051,7 +2022,6 @@ "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/types": "^7.4.4", @@ -2669,6 +2639,7 @@ "resolved": "https://registry.npmjs.org/@expo/metro-runtime/-/metro-runtime-4.0.1.tgz", "integrity": "sha512-CRpbLvdJ1T42S+lrYa1iZp1KfDeBp4oeZOK3hdpiS5n0vR0nhD6sC1gGF0sTboCTp64tLteikz5Y3j53dvgOIw==", "license": "MIT", + "peer": true, "peerDependencies": { "react-native": "*" } @@ -3701,6 +3672,7 @@ "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-6.1.18.tgz", "integrity": "sha512-mIT9MiL/vMm4eirLcmw2h6h/Nm5FICtnYSdohq4vTLA2FF/6PNhByM7s8ffqoVfE5L0uAa6Xda1B7oddolUiGg==", "license": "MIT", + "peer": true, "dependencies": { "@react-navigation/core": "^6.4.17", "escape-string-regexp": "^4.0.0", @@ -3865,6 +3837,7 @@ "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" @@ -4467,6 +4440,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -5482,7 +5456,6 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "license": "BSD-2-Clause", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -5607,6 +5580,7 @@ "resolved": "https://registry.npmjs.org/expo/-/expo-52.0.48.tgz", "integrity": "sha512-/HR/vuo57KGEWlvF3GWaquwEAjXuA5hrOCsaLcZ3pMSA8mQ27qKd1jva4GWzpxXYedlzs/7LLP1XpZo6hXTsog==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.20.0", "@expo/cli": "0.22.27", @@ -9079,6 +9053,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -9162,6 +9137,7 @@ "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.76.9.tgz", "integrity": "sha512-+LRwecWmTDco7OweGsrECIqJu0iyrREd6CTCgC/uLLYipiHvk+MH9nd6drFtCw/6Blz6eoKTcH9YTTJusNtrWg==", "license": "MIT", + "peer": true, "dependencies": { "@jest/create-cache-key-function": "^29.6.3", "@react-native/assets-registry": "0.76.9", @@ -9263,6 +9239,7 @@ "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.12.0.tgz", "integrity": "sha512-ukk5PxcF4p3yu6qMZcmeiZgowhb5AsKRnil54YFUUAXVIS7PJcMHGGC+q44fCiBg44/1AJk5njGMez1m9H0BVQ==", "license": "MIT", + "peer": true, "peerDependencies": { "react": "*", "react-native": "*" @@ -9273,6 +9250,7 @@ "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.4.0.tgz", "integrity": "sha512-c7zc7Zwjty6/pGyuuvh9gK3YBYqHPOxrhXfG1lF4gHlojQSmIx2piNbNaV+Uykj+RDTmFXK0e/hA+fucw/Qozg==", "license": "MIT", + "peer": true, "dependencies": { "react-freeze": "^1.0.0", "warn-once": "^0.1.0" diff --git a/src/navigation/TabNavigator.tsx b/src/navigation/TabNavigator.tsx index 5e49896..2119db0 100644 --- a/src/navigation/TabNavigator.tsx +++ b/src/navigation/TabNavigator.tsx @@ -6,7 +6,6 @@ import { colors, borderRadius, typography } from '../theme/colors'; // Screens import FlowScreen from '../screens/FlowScreen'; -import VaultScreen from '../screens/VaultScreen'; import SentinelScreen from '../screens/SentinelScreen'; import HeritageScreen from '../screens/HeritageScreen'; import MeScreen from '../screens/MeScreen'; @@ -89,22 +88,6 @@ export default function TabNavigator() { ), }} /> - ( - - ), - tabBarStyle: styles.tabBarDark, - }} - /> (null); + const [showVault, setShowVault] = useState(false); const [newHeirName, setNewHeirName] = useState(''); const [newHeirEmail, setNewHeirEmail] = useState(''); const [newHeirLevel, setNewHeirLevel] = useState(1); @@ -147,6 +152,26 @@ export default function HeritageScreen() { + {/* Shadow Vault Access */} + + + + + + Shadow Vault + + Access sealed assets from inside the Heritage layer. + + + setShowVault(true)} + activeOpacity={0.8} + > + Open + + + {/* Release Stages Info */} @@ -366,6 +391,24 @@ export default function HeritageScreen() { + {/* Vault Modal */} + setShowVault(false)} + > + + + setShowVault(false)} + activeOpacity={0.85} + > + + + + + {/* Heir Detail Modal */} (null); + const [showSpiritKeysModal, setShowSpiritKeysModal] = useState(false); + const [showTideModal, setShowTideModal] = useState(false); + const [showSanctumModal, setShowSanctumModal] = useState(false); + const [showCaptainFull, setShowCaptainFull] = useState(false); + const [showTriggerModal, setShowTriggerModal] = useState(false); + const [tideLevel, setTideLevel] = useState<'low' | 'high' | 'red'>('low'); + const [tideChannels, setTideChannels] = useState({ + push: true, + email: true, + sms: false, + emergency: false, + }); + const [tideCadence, setTideCadence] = useState<'daily' | 'weekly' | 'monthly'>('weekly'); + const [sanctumBiometric, setSanctumBiometric] = useState({ + vaultEntry: true, + highRisk: true, + export: true, + }); + const [sanctumArchive, setSanctumArchive] = useState<'off' | 'standard' | 'strict'>('standard'); + const [sanctumRehearsal, setSanctumRehearsal] = useState<'monthly' | 'quarterly'>('quarterly'); + const [triggerDisconnectDays, setTriggerDisconnectDays] = useState(30); + const [triggerGraceDays, setTriggerGraceDays] = useState(15); + const [triggerSource, setTriggerSource] = useState<'dual' | 'subscription' | 'activity'>('dual'); + const [triggerKillSwitch, setTriggerKillSwitch] = useState(true); const handleOpenLink = (url: string) => { Linking.openURL(url).catch(() => {}); @@ -196,7 +220,11 @@ export default function MeScreen() { {/* Profile Card */} - + setShowCaptainFull(true)} + > @@ -215,7 +243,7 @@ export default function MeScreen() { - + {/* Quick Stats */} @@ -258,6 +286,17 @@ export default function MeScreen() { styles.menuItem, index < captainProtocols.length - 1 && styles.menuItemBorder ]} + onPress={() => { + if (item.id === 'spirit-keys') { + setShowSpiritKeysModal(true); + } + if (item.id === 'tide-notifications') { + setShowTideModal(true); + } + if (item.id === 'sanctum-settings') { + setShowSanctumModal(true); + } + }} > @@ -290,6 +329,11 @@ export default function MeScreen() { styles.menuItem, index < settingsMenu.length - 1 && styles.menuItemBorder ]} + onPress={() => { + if (item.id === 'trigger') { + setShowTriggerModal(true); + } + }} > @@ -380,6 +424,571 @@ export default function MeScreen() { + + + {/* Spirit Keys Modal */} + setShowSpiritKeysModal(false)} + > + + + + + + + Mnemonic Split Protocol + + + + + + 12 words split into two sealed shards + + + + + + + Server Shard (1–6) + Encrypted + + •••• •••• •••• •••• •••• •••• + + + + + Heir Shard (7–12) + Pending Release + + •••• •••• •••• •••• •••• •••• + + + + + + Heir shard auto-delivers on confirmed passing event. + + + + + + setShowSpiritKeysModal(false)} + > + Close + + + + + + {/* Sanctum Settings Modal */} + setShowSanctumModal(false)} + > + + + + + + + Sanctum Settings + + + + IDENTITY SEPARATION + + Flow Identity + Phone / Social + + + Vault Identity + Device Key (No Account) + + + + + BIOMETRIC POLICY + {[ + { key: 'vaultEntry', label: 'Vault Entry' }, + { key: 'highRisk', label: 'High-Risk Reveal' }, + { key: 'export', label: 'Export Cipher Pack' }, + ].map((item) => { + const isOn = sanctumBiometric[item.key as keyof typeof sanctumBiometric]; + return ( + + setSanctumBiometric((prev) => ({ + ...prev, + [item.key]: !prev[item.key as keyof typeof prev], + })) + } + activeOpacity={0.85} + > + {item.label} + + {isOn ? 'ON' : 'OFF'} + + + ); + })} + + + + ARCHIVE POLICY + + {[ + { key: 'off', label: 'Off' }, + { key: 'standard', label: 'Standard' }, + { key: 'strict', label: 'Strict' }, + ].map((item) => { + const isActive = sanctumArchive === item.key; + return ( + setSanctumArchive(item.key as typeof sanctumArchive)} + activeOpacity={0.85} + > + + {item.label} + + + ); + })} + + Strict mode shreds plaintext immediately after seal. + + + + MNEMONIC REHEARSAL + + {[ + { key: 'monthly', label: 'Monthly' }, + { key: 'quarterly', label: 'Quarterly' }, + ].map((item) => { + const isActive = sanctumRehearsal === item.key; + return ( + setSanctumRehearsal(item.key as typeof sanctumRehearsal)} + activeOpacity={0.85} + > + + {item.label} + + + ); + })} + + Last rehearsal passed: 42 days ago. + + + + ONE-WAY ARCHIVE + + Flow → Vault + Enabled + + + Auto Desensitize + High + + + + + ACCOUNT FUSE + + + + Deleting Flow clears server hash links to prevent misrelease. + + + + + + EXPORTS & AUDIT + + Cipher Pack Export + View + + + Audit Log + View + + + + + setShowSanctumModal(false)} + > + + Save + + setShowSanctumModal(false)} + > + + Close + + + + + + + {/* Tide Notifications Modal */} + setShowTideModal(false)} + > + setShowTideModal(false)} + > + {}}> + + + + + + Tide Notifications + + + + ALERT LEVEL + + {[ + { key: 'low', label: 'Low Tide' }, + { key: 'high', label: 'High Tide' }, + { key: 'red', label: 'Red Tide' }, + ].map((item) => { + const isActive = tideLevel === item.key; + return ( + setTideLevel(item.key as typeof tideLevel)} + activeOpacity={0.85} + > + + {item.label} + + + ); + })} + + + + + CHANNELS + + {[ + { key: 'push', label: 'App Push', icon: 'notifications' }, + { key: 'email', label: 'Email', icon: 'mail' }, + { key: 'sms', label: 'SMS', icon: 'chatbubble' }, + { key: 'emergency', label: 'Emergency', icon: 'alert' }, + ].map((item) => { + const isActive = tideChannels[item.key as keyof typeof tideChannels]; + return ( + + setTideChannels((prev) => ({ + ...prev, + [item.key]: !prev[item.key as keyof typeof prev], + })) + } + activeOpacity={0.85} + > + + + {item.label} + + + ); + })} + + + + + CADENCE + + {[ + { key: 'daily', label: 'Daily' }, + { key: 'weekly', label: 'Weekly' }, + { key: 'monthly', label: 'Monthly' }, + ].map((item) => { + const isActive = tideCadence === item.key; + return ( + setTideCadence(item.key as typeof tideCadence)} + activeOpacity={0.85} + > + + {item.label} + + + ); + })} + + + + + + + Last confirmation: 3 days ago · Next reminder in 4 days. + + + + + setShowTideModal(false)} + > + + Save + + setShowTideModal(false)} + > + + Close + + + + + + + + {/* Captain Fullscreen */} + setShowCaptainFull(false)} + > + + + + + setShowCaptainFull(false)} + activeOpacity={0.8} + > + + + Captain + + + + + + + + + Captain + MASTER OF THE SANCTUM + + + Pro Member + + + + + IDENTITY + + Flow Identity + Phone / Social + + + Vault Identity + Device Key + + + + + STATUS + + Sentinel + Normal + + + Last Check + 3 days ago + + + + + + + + + {/* Trigger Logic Modal */} + setShowTriggerModal(false)} + > + + + + + + + Trigger Logic + + + + DISCONNECT WINDOW + + {[14, 30, 60].map((days) => { + const isActive = triggerDisconnectDays === days; + return ( + setTriggerDisconnectDays(days)} + activeOpacity={0.85} + > + + {days} Days + + + ); + })} + + + + + GRACE PERIOD + + {[7, 15, 30].map((days) => { + const isActive = triggerGraceDays === days; + return ( + setTriggerGraceDays(days)} + activeOpacity={0.85} + > + + {days} Days + + + ); + })} + + + + + TRIGGER SOURCE + + {[ + { key: 'dual', label: 'Subscription + Activity' }, + { key: 'subscription', label: 'Subscription Only' }, + { key: 'activity', label: 'Activity Only' }, + ].map((item) => { + const isActive = triggerSource === item.key; + return ( + setTriggerSource(item.key as typeof triggerSource)} + activeOpacity={0.85} + > + + {item.label} + + + ); + })} + + + + + KILL SWITCH + setTriggerKillSwitch(!triggerKillSwitch)} + activeOpacity={0.85} + > + SMS One-Tap Reset + + {triggerKillSwitch ? 'ON' : 'OFF'} + + + + + + ALERT PATH + + + T+0 App/Email + + + T+15 SMS + + + T+30 Heir Handshake + + + + + + setShowTriggerModal(false)} + > + + Save + + setShowTriggerModal(false)} + > + + Close + + + + + ); } @@ -606,6 +1215,235 @@ const styles = StyleSheet.create({ fontSize: typography.fontSize.sm, color: colors.me.textSecondary, }, + mnemonicCard: { + backgroundColor: 'transparent', + borderRadius: 0, + padding: 0, + marginBottom: spacing.lg, + borderWidth: 0, + }, + mnemonicHeader: { + flexDirection: 'row', + alignItems: 'center', + gap: spacing.sm, + }, + mnemonicHeaderText: { + flex: 1, + }, + mnemonicTitle: { + fontSize: typography.fontSize.base, + fontWeight: '600', + color: colors.me.text, + marginBottom: 2, + }, + mnemonicSubtitle: { + fontSize: typography.fontSize.sm, + color: colors.me.textSecondary, + }, + mnemonicBody: { + marginTop: spacing.md, + gap: spacing.md, + }, + mnemonicShard: { + padding: spacing.base, + borderRadius: borderRadius.lg, + backgroundColor: colors.nautical.paleAqua, + borderWidth: 0, + }, + mnemonicShardRow: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + marginBottom: spacing.sm, + }, + mnemonicShardLabel: { + fontSize: typography.fontSize.sm, + fontWeight: '600', + color: colors.me.text, + }, + mnemonicShardStatus: { + fontSize: typography.fontSize.xs, + color: colors.me.primary, + fontWeight: '600', + letterSpacing: 0.6, + }, + mnemonicShardText: { + fontSize: typography.fontSize.base, + color: colors.me.textSecondary, + letterSpacing: 2, + }, + mnemonicRule: { + flexDirection: 'row', + alignItems: 'center', + gap: spacing.sm, + backgroundColor: colors.nautical.lightMint, + borderRadius: borderRadius.lg, + padding: spacing.base, + }, + mnemonicRuleText: { + flex: 1, + fontSize: typography.fontSize.sm, + color: colors.me.text, + }, + tideSection: { + marginBottom: spacing.lg, + }, + tideLabel: { + fontSize: typography.fontSize.xs, + color: colors.me.textSecondary, + letterSpacing: typography.letterSpacing.wide, + fontWeight: '700', + marginBottom: spacing.sm, + }, + tideRow: { + flexDirection: 'row', + gap: spacing.sm, + }, + tideButton: { + flex: 1, + paddingVertical: spacing.sm, + borderRadius: borderRadius.lg, + backgroundColor: colors.nautical.paleAqua, + borderWidth: 1, + borderColor: colors.me.cardBorder, + alignItems: 'center', + }, + tideButtonActive: { + borderColor: colors.me.primary, + backgroundColor: colors.nautical.lightMint, + }, + tideButtonText: { + fontSize: typography.fontSize.sm, + color: colors.me.textSecondary, + fontWeight: '600', + }, + tideButtonTextActive: { + color: colors.me.primary, + }, + channelGrid: { + flexDirection: 'row', + flexWrap: 'wrap', + gap: spacing.sm, + }, + channelCard: { + width: '48%', + flexDirection: 'row', + alignItems: 'center', + gap: spacing.sm, + paddingVertical: spacing.sm, + paddingHorizontal: spacing.base, + borderRadius: borderRadius.lg, + backgroundColor: colors.nautical.paleAqua, + borderWidth: 1, + borderColor: colors.me.cardBorder, + }, + channelCardActive: { + borderColor: colors.me.primary, + backgroundColor: colors.nautical.lightMint, + }, + channelText: { + fontSize: typography.fontSize.sm, + color: colors.me.textSecondary, + fontWeight: '600', + }, + channelTextActive: { + color: colors.me.primary, + }, + tideHint: { + flexDirection: 'row', + alignItems: 'center', + gap: spacing.sm, + backgroundColor: colors.nautical.lightMint, + borderRadius: borderRadius.lg, + padding: spacing.base, + }, + tideHintText: { + flex: 1, + fontSize: typography.fontSize.sm, + color: colors.me.text, + }, + sanctumSection: { + marginBottom: spacing.lg, + }, + sanctumRow: { + flexDirection: 'row', + justifyContent: 'space-between', + paddingVertical: spacing.sm, + borderBottomWidth: 1, + borderBottomColor: colors.me.cardBorder, + }, + sanctumText: { + fontSize: typography.fontSize.sm, + color: colors.me.text, + fontWeight: '600', + }, + sanctumValue: { + fontSize: typography.fontSize.sm, + color: colors.me.textSecondary, + }, + sanctumToggleRow: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + paddingVertical: spacing.sm, + borderBottomWidth: 1, + borderBottomColor: colors.me.cardBorder, + }, + sanctumToggle: { + minWidth: 52, + paddingVertical: 4, + borderRadius: borderRadius.full, + backgroundColor: colors.nautical.paleAqua, + alignItems: 'center', + }, + sanctumToggleOn: { + backgroundColor: colors.nautical.lightMint, + }, + sanctumToggleText: { + fontSize: typography.fontSize.xs, + color: colors.me.primary, + fontWeight: '700', + letterSpacing: 0.6, + }, + sanctumHint: { + marginTop: spacing.sm, + fontSize: typography.fontSize.sm, + color: colors.me.textSecondary, + }, + sanctumAlert: { + flexDirection: 'row', + alignItems: 'center', + gap: spacing.sm, + backgroundColor: '#FFE5E5', + borderRadius: borderRadius.lg, + padding: spacing.base, + }, + sanctumAlertText: { + flex: 1, + fontSize: typography.fontSize.sm, + color: colors.nautical.coral, + }, + confirmPulseButton: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + gap: spacing.sm, + backgroundColor: colors.nautical.lightMint, + borderRadius: borderRadius.lg, + paddingVertical: spacing.md, + flex: 1, + }, + confirmPulseText: { + fontSize: typography.fontSize.base, + fontWeight: '700', + color: colors.nautical.teal, + letterSpacing: typography.letterSpacing.wide, + }, + tideModalButtons: { + flexDirection: 'row', + gap: spacing.sm, + marginBottom: spacing.md, + }, // Abandon Button abandonButton: { flexDirection: 'row', @@ -746,4 +1584,178 @@ const styles = StyleSheet.create({ color: colors.me.primary, fontWeight: '600', }, + spiritOverlay: { + flex: 1, + backgroundColor: 'rgba(26, 58, 74, 0.5)', + justifyContent: 'center', + padding: spacing.lg, + }, + spiritModal: { + backgroundColor: colors.me.cardBackground, + borderRadius: borderRadius.xxl, + padding: spacing.xl, + ...shadows.medium, + maxHeight: '80%', + }, + spiritHeader: { + flexDirection: 'row', + alignItems: 'center', + marginBottom: spacing.md, + paddingBottom: spacing.md, + borderBottomWidth: 1, + borderBottomColor: colors.me.cardBorder, + }, + spiritIcon: { + width: 44, + height: 44, + borderRadius: 14, + backgroundColor: colors.nautical.lightMint, + justifyContent: 'center', + alignItems: 'center', + marginRight: spacing.md, + }, + spiritTitle: { + fontSize: typography.fontSize.lg, + fontWeight: '700', + color: colors.me.text, + }, + spiritScroll: { + marginBottom: spacing.md, + }, + captainContainer: { + flex: 1, + backgroundColor: colors.me.background, + }, + captainGradient: { + flex: 1, + }, + captainSafeArea: { + flex: 1, + }, + captainHeader: { + flexDirection: 'row', + alignItems: 'center', + paddingHorizontal: spacing.base, + paddingTop: spacing.md, + paddingBottom: spacing.sm, + }, + captainBack: { + width: 36, + height: 36, + borderRadius: 18, + backgroundColor: colors.me.cardBackground, + alignItems: 'center', + justifyContent: 'center', + }, + captainTitle: { + flex: 1, + textAlign: 'center', + fontSize: typography.fontSize.lg, + fontWeight: '700', + color: colors.me.text, + }, + captainSpacer: { + width: 36, + }, + captainScroll: { + flex: 1, + }, + captainContent: { + paddingHorizontal: spacing.base, + paddingBottom: spacing.xl, + }, + captainProfileCard: { + backgroundColor: colors.me.cardBackground, + borderRadius: borderRadius.xl, + padding: spacing.lg, + alignItems: 'center', + marginBottom: spacing.lg, + ...shadows.soft, + }, + captainAvatar: { + width: 88, + height: 88, + borderRadius: 28, + backgroundColor: colors.nautical.teal, + justifyContent: 'center', + alignItems: 'center', + marginBottom: spacing.sm, + }, + captainName: { + fontSize: typography.fontSize.xl, + fontWeight: '700', + color: colors.me.text, + marginBottom: 4, + }, + captainRole: { + fontSize: typography.fontSize.xs, + fontWeight: '600', + color: colors.me.textSecondary, + letterSpacing: typography.letterSpacing.wider, + marginBottom: spacing.sm, + }, + captainBadge: { + flexDirection: 'row', + alignItems: 'center', + gap: 4, + backgroundColor: `${colors.nautical.gold}15`, + paddingHorizontal: spacing.sm, + paddingVertical: 3, + borderRadius: borderRadius.full, + }, + captainBadgeText: { + fontSize: typography.fontSize.xs, + fontWeight: '600', + color: colors.nautical.gold, + }, + captainSection: { + backgroundColor: colors.me.cardBackground, + borderRadius: borderRadius.xl, + padding: spacing.base, + marginBottom: spacing.md, + ...shadows.soft, + }, + captainSectionTitle: { + fontSize: typography.fontSize.xs, + fontWeight: '700', + color: colors.me.textSecondary, + letterSpacing: typography.letterSpacing.widest, + marginBottom: spacing.sm, + }, + captainRow: { + flexDirection: 'row', + justifyContent: 'space-between', + paddingVertical: spacing.sm, + borderBottomWidth: 1, + borderBottomColor: colors.me.cardBorder, + }, + captainLabel: { + fontSize: typography.fontSize.sm, + color: colors.me.textSecondary, + }, + captainValue: { + fontSize: typography.fontSize.sm, + color: colors.me.text, + fontWeight: '600', + }, + triggerStepRow: { + flexDirection: 'row', + gap: spacing.sm, + }, + alertPathRow: { + flexDirection: 'row', + flexWrap: 'wrap', + gap: spacing.sm, + }, + alertChip: { + backgroundColor: colors.nautical.lightMint, + paddingHorizontal: spacing.sm, + paddingVertical: 6, + borderRadius: borderRadius.full, + }, + alertChipText: { + fontSize: typography.fontSize.xs, + color: colors.me.primary, + fontWeight: '600', + }, }); diff --git a/src/screens/VaultScreen.tsx b/src/screens/VaultScreen.tsx index 5997e1d..25daf08 100644 --- a/src/screens/VaultScreen.tsx +++ b/src/screens/VaultScreen.tsx @@ -9,6 +9,8 @@ import { TextInput, SafeAreaView, Animated, + Linking, + Alert, } from 'react-native'; import { LinearGradient } from 'expo-linear-gradient'; import { Ionicons, Feather, MaterialCommunityIcons, FontAwesome5 } from '@expo/vector-icons'; @@ -18,7 +20,7 @@ import BiometricModal from '../components/common/BiometricModal'; // Asset type configuration with nautical theme const assetTypeConfig: Record = { - game_account: { icon: 'gamepad', iconType: 'fontawesome5', label: 'Digital Account' }, + game_account: { icon: 'account-key', iconType: 'material', label: 'Account Login' }, private_key: { icon: 'key', iconType: 'fontawesome5', label: 'Secret Key' }, document: { icon: 'scroll', iconType: 'fontawesome5', label: 'Document' }, photo: { icon: 'image', iconType: 'ionicons', label: 'Sealed Photo' }, @@ -26,6 +28,13 @@ const assetTypeConfig: Record(null); + const [showDetail, setShowDetail] = useState(false); + const [showGuardedBiometric, setShowGuardedBiometric] = useState(false); + const [showKeyPreview, setShowKeyPreview] = useState(false); + const [addStep, setAddStep] = useState(1); + const [addMethod, setAddMethod] = useState<'text' | 'file' | 'scan'>('text'); + const [addVerified, setAddVerified] = useState(false); + const [rehearsalConfirmed, setRehearsalConfirmed] = useState(false); + const [showAddBiometric, setShowAddBiometric] = useState(false); + const [accountProvider, setAccountProvider] = useState<'bank' | 'steam' | 'facebook' | 'custom'>('bank'); useEffect(() => { if (!isUnlocked) { @@ -129,8 +148,20 @@ export default function VaultScreen() { setIsUnlocked(true); }; + const resetAddFlow = () => { + setAddStep(1); + setAddMethod('text'); + setAddVerified(false); + setRehearsalConfirmed(false); + setSelectedType('custom'); + setNewLabel(''); + setAccountProvider('bank'); + }; + const handleAddAsset = () => { if (!newLabel.trim()) return; + if (!addVerified) return; + if (selectedType === 'private_key' && !rehearsalConfirmed) return; const newAsset: VaultAsset = { id: Date.now().toString(), @@ -145,6 +176,8 @@ export default function VaultScreen() { setNewLabel(''); setSelectedType('custom'); setShowAddModal(false); + setAddVerified(false); + setRehearsalConfirmed(false); setShowUploadSuccess(true); setTimeout(() => setShowUploadSuccess(false), 2500); @@ -158,6 +191,86 @@ export default function VaultScreen() { }); }; + const handleOpenDetail = (asset: VaultAsset) => { + setSelectedAsset(asset); + setShowDetail(true); + setShowKeyPreview(false); + }; + + const handleCloseDetail = () => { + setShowDetail(false); + setSelectedAsset(null); + setShowKeyPreview(false); + setShowGuardedBiometric(false); + }; + + const handleGuardedAccess = () => { + setShowGuardedBiometric(true); + }; + + const handleGuardedSuccess = () => { + setShowGuardedBiometric(false); + setShowKeyPreview(true); + }; + + const handleAddVerification = () => { + setShowAddBiometric(true); + }; + + const handleAddVerificationSuccess = () => { + setShowAddBiometric(false); + setAddVerified(true); + }; + + const openProviderLogin = async () => { + if (accountProvider === 'bank') { + Alert.alert( + 'Bank App Needed', + 'Provide the bank app deep link scheme to enable one-tap login.' + ); + return; + } + + const providerLinks = { + steam: { + app: 'steam://openurl/https://store.steampowered.com/login/', + web: 'https://store.steampowered.com/login/', + }, + facebook: { + app: 'fb://facewebmodal/f?href=https://www.facebook.com/login', + web: 'https://www.facebook.com/login', + }, + custom: { + app: '', + web: '', + }, + } as const; + + const target = providerLinks[accountProvider]; + if (!target?.app) { + return; + } + + const canOpen = await Linking.canOpenURL(target.app); + if (canOpen) { + await Linking.openURL(target.app); + } else if (target.web) { + await Linking.openURL(target.web); + } + }; + + const selectedConfig = selectedAsset ? assetTypeConfig[selectedAsset.type] : null; + const detailHeading = selectedAsset?.type === 'private_key' + ? 'Key Material' + : selectedConfig?.label || 'Vault Asset'; + const detailMetaLabel = selectedAsset?.type === 'private_key' ? 'KEY MATERIAL' : 'ASSET CLASS'; + const detailMetaValue = selectedAsset?.type === 'private_key' + ? '12/24 Words' + : selectedConfig?.label || '--'; + const canSeal = !!newLabel.trim() + && addVerified + && (selectedType !== 'private_key' || rehearsalConfirmed); + // Lock screen if (!isUnlocked) { return ( @@ -253,6 +366,7 @@ export default function VaultScreen() { key={asset.id} style={styles.assetCard} activeOpacity={0.7} + onPress={() => handleOpenDetail(asset)} > {renderAssetTypeIcon(config, 22, colors.vault.primary)} @@ -277,7 +391,10 @@ export default function VaultScreen() { {/* Add Button */} setShowAddModal(true)} + onPress={() => { + resetAddFlow(); + setShowAddModal(true); + }} activeOpacity={0.9} > Add New Treasure - - TREASURE TYPE - - {(Object.keys(assetTypeConfig) as VaultAssetType[]).map((type) => { - const config = assetTypeConfig[type]; - const isSelected = selectedType === type; + + + {['Type', 'Method', 'Verify'].map((label, index) => { + const stepIndex = index + 1; + const isActive = addStep === stepIndex; + const isDone = addStep > stepIndex; return ( - setSelectedType(type)} - > - - {renderAssetTypeIcon(config, 22, isSelected ? colors.nautical.teal : colors.nautical.sage)} + + + + {stepIndex} + - - {config.label} + + {label} - + ); })} - - - TREASURE NAME - - - - - - Your treasure will be encrypted and sealed. Original data will be securely destroyed. - + {addStep === 1 && ( + <> + TREASURE TYPE + + {(Object.keys(assetTypeConfig) as VaultAssetType[]).map((type) => { + const config = assetTypeConfig[type]; + const isSelected = selectedType === type; + return ( + setSelectedType(type)} + > + + {renderAssetTypeIcon(config, 22, isSelected ? colors.nautical.teal : colors.nautical.sage)} + + + {config.label} + + + ); + })} + + + )} + + {addStep === 2 && ( + <> + {selectedType !== 'game_account' && ( + <> + CAPTURE METHOD + + {[ + { key: 'text', label: 'Text', icon: 'text' }, + { key: 'file', label: 'File', icon: 'file-tray' }, + { key: 'scan', label: 'Scan', icon: 'camera' }, + ].map((item) => { + const isActive = addMethod === item.key; + return ( + setAddMethod(item.key as typeof addMethod)} + > + + + {item.label} + + + ); + })} + + + )} + + {selectedType === 'game_account' && ( + <> + ACCOUNT PROVIDER + + {accountProviderOptions.map((option) => { + const isSelected = accountProvider === option.key; + return ( + setAccountProvider(option.key as typeof accountProvider)} + > + + {renderAssetTypeIcon( + { icon: option.icon, iconType: option.iconType, label: option.label }, + 22, + isSelected ? colors.nautical.teal : colors.nautical.sage + )} + + + {option.label} + + + ); + })} + + + + Open App to Login + + + )} + + TREASURE NAME + + + + + + Data is encrypted on-device. Plaintext is shredded after sealing. + + + + )} + + {addStep === 3 && ( + <> + IDENTITY VERIFICATION + + + + Biometric required before sealing. + + + + {addVerified ? 'Verified' : 'Verify Now'} + + + + + {selectedType === 'private_key' && ( + setRehearsalConfirmed(!rehearsalConfirmed)} + activeOpacity={0.8} + > + + + I rehearsed the mnemonic once (required). + + + )} + + + + + Only a masked shard can be revealed, and access is time-limited. + + + + )} + { - setShowAddModal(false); - setNewLabel(''); + if (addStep === 1) { + setShowAddModal(false); + } else { + setAddStep(addStep - 1); + } }} > - Cancel + + {addStep === 1 ? 'Cancel' : 'Back'} + - - setAddStep(addStep + 1)} > - - Seal Treasure - - + + Continue + + + ) : ( + + + + Seal Treasure + + + )} + + setShowAddBiometric(false)} + title="Confirm Identity" + message="Verify before sealing this treasure" + isDark + /> + + {/* Detail Modal */} + + + + + + + + + {detailHeading} + {selectedAsset?.type === 'private_key' && ( + + HIGH-RISK + + )} + + + + + + + + + SEALED ASSET + {selectedAsset?.label} + Encrypted at rest · No plaintext stored + + + + + + CREATED + + {selectedAsset ? formatDate(selectedAsset.createdAt) : '--'} + + + + LAST VERIFIED + + {selectedAsset ? formatDate(selectedAsset.updatedAt) : '--'} + + + + STORAGE + Cipher Pack + + + {detailMetaLabel} + {detailMetaValue} + + + + + CONTROLLED ACTIONS + + + View Encrypted Digest + + + + Export Cipher Pack + + + + Reset Sentinel Timer + + + + + + + Guarded Reveal + + + Plaintext access requires biometric verification and a memory rehearsal step. + + + Begin Verification + + {showKeyPreview && ( + + MNEMONIC SHARD (MASKED) + ocean-anchored-ember-veil + + )} + + + + + + Any reveal attempt is time-limited and logged. Screenshots are blocked by policy. + + + + + + + + setShowGuardedBiometric(false)} + title="Verify Access" + message="Confirm to reveal a masked shard of the mnemonic" + isDark + /> + ); } @@ -636,6 +1070,53 @@ const styles = StyleSheet.create({ fontWeight: '600', color: colors.nautical.navy, }, + stepRow: { + flexDirection: 'row', + justifyContent: 'space-between', + marginBottom: spacing.lg, + }, + stepItem: { + alignItems: 'center', + flex: 1, + }, + stepCircle: { + width: 28, + height: 28, + borderRadius: 14, + borderWidth: 1, + borderColor: colors.nautical.lightMint, + alignItems: 'center', + justifyContent: 'center', + backgroundColor: colors.nautical.paleAqua, + }, + stepCircleActive: { + borderColor: colors.nautical.teal, + backgroundColor: colors.nautical.lightMint, + }, + stepCircleDone: { + borderColor: colors.nautical.teal, + backgroundColor: colors.nautical.teal, + }, + stepNumber: { + fontSize: typography.fontSize.xs, + color: colors.nautical.sage, + fontWeight: '600', + }, + stepNumberActive: { + color: colors.nautical.teal, + }, + stepNumberDone: { + color: colors.nautical.cream, + }, + stepLabel: { + fontSize: typography.fontSize.xs, + color: colors.nautical.sage, + marginTop: spacing.xs, + }, + stepLabelActive: { + color: colors.nautical.teal, + fontWeight: '600', + }, modalLabel: { fontSize: typography.fontSize.xs, color: colors.nautical.sage, @@ -643,6 +1124,49 @@ const styles = StyleSheet.create({ letterSpacing: typography.letterSpacing.wider, fontWeight: '600', }, + methodRow: { + flexDirection: 'row', + gap: spacing.sm, + marginBottom: spacing.lg, + }, + methodButton: { + flex: 1, + paddingVertical: spacing.sm, + borderRadius: borderRadius.lg, + alignItems: 'center', + gap: spacing.xs, + backgroundColor: colors.nautical.paleAqua, + borderWidth: 1, + borderColor: colors.nautical.lightMint, + }, + methodButtonActive: { + borderColor: colors.nautical.teal, + backgroundColor: colors.nautical.lightMint, + }, + methodLabel: { + fontSize: typography.fontSize.sm, + color: colors.nautical.sage, + fontWeight: '600', + }, + methodLabelActive: { + color: colors.nautical.teal, + }, + loginButton: { + marginTop: spacing.sm, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + gap: spacing.sm, + backgroundColor: colors.nautical.teal, + paddingVertical: spacing.sm, + borderRadius: borderRadius.full, + }, + loginButtonText: { + color: colors.nautical.cream, + fontSize: typography.fontSize.sm, + fontWeight: '700', + letterSpacing: 0.6, + }, typeScroll: { marginBottom: spacing.lg, }, @@ -740,9 +1264,267 @@ const styles = StyleSheet.create({ paddingVertical: spacing.md, gap: spacing.sm, }, + confirmButtonGradientDisabled: { + opacity: 0.5, + }, confirmButtonText: { fontSize: typography.fontSize.base, color: '#fff', fontWeight: '600', }, + verifyCard: { + backgroundColor: colors.nautical.paleAqua, + borderRadius: borderRadius.lg, + padding: spacing.base, + marginBottom: spacing.md, + borderWidth: 1, + borderColor: colors.nautical.lightMint, + gap: spacing.sm, + }, + verifyRow: { + flexDirection: 'row', + alignItems: 'center', + gap: spacing.sm, + }, + verifyText: { + color: colors.nautical.navy, + fontSize: typography.fontSize.sm, + }, + verifyButton: { + alignSelf: 'flex-start', + paddingHorizontal: spacing.md, + paddingVertical: spacing.sm, + borderRadius: borderRadius.full, + backgroundColor: colors.nautical.teal, + }, + verifyButtonDone: { + backgroundColor: colors.nautical.sage, + }, + verifyButtonText: { + color: colors.nautical.cream, + fontWeight: '700', + }, + rehearsalRow: { + flexDirection: 'row', + alignItems: 'center', + gap: spacing.sm, + marginBottom: spacing.md, + }, + rehearsalText: { + color: colors.nautical.navy, + fontSize: typography.fontSize.sm, + flex: 1, + }, + detailContainer: { + flex: 1, + backgroundColor: colors.vault.background, + }, + detailGradient: { + flex: 1, + }, + detailSafeArea: { + flex: 1, + }, + detailHeader: { + paddingHorizontal: spacing.lg, + paddingTop: spacing.lg, + paddingBottom: spacing.md, + flexDirection: 'row', + alignItems: 'center', + gap: spacing.sm, + }, + detailBackButton: { + width: 36, + height: 36, + borderRadius: 18, + backgroundColor: 'rgba(255, 255, 255, 0.08)', + alignItems: 'center', + justifyContent: 'center', + }, + detailTitle: { + flex: 1, + fontSize: typography.fontSize.lg, + color: colors.vault.text, + fontWeight: '700', + letterSpacing: typography.letterSpacing.wide, + }, + riskBadge: { + backgroundColor: `${colors.vault.warning}25`, + borderRadius: borderRadius.full, + paddingHorizontal: spacing.sm, + paddingVertical: 4, + }, + riskBadgeText: { + fontSize: typography.fontSize.xs, + color: colors.vault.warning, + fontWeight: '700', + letterSpacing: 1, + }, + detailScroll: { + flex: 1, + }, + detailContent: { + padding: spacing.lg, + paddingTop: spacing.sm, + gap: spacing.lg, + }, + detailHeroCard: { + backgroundColor: colors.vault.cardBackground, + borderRadius: borderRadius.xl, + padding: spacing.lg, + borderWidth: 1, + borderColor: colors.vault.cardBorder, + flexDirection: 'row', + gap: spacing.base, + alignItems: 'center', + }, + detailHeroIcon: { + width: 54, + height: 54, + borderRadius: 27, + backgroundColor: 'rgba(184, 224, 229, 0.15)', + alignItems: 'center', + justifyContent: 'center', + }, + detailHeroInfo: { + flex: 1, + }, + detailHeroLabel: { + fontSize: typography.fontSize.xs, + color: colors.vault.textSecondary, + letterSpacing: 1, + fontWeight: '600', + marginBottom: 4, + }, + detailHeroTitle: { + fontSize: typography.fontSize.lg, + color: colors.vault.text, + fontWeight: '700', + marginBottom: 4, + }, + detailHeroSubtitle: { + fontSize: typography.fontSize.sm, + color: colors.vault.textSecondary, + }, + metaGrid: { + flexDirection: 'row', + flexWrap: 'wrap', + gap: spacing.md, + }, + metaCard: { + width: '48%', + backgroundColor: 'rgba(255, 255, 255, 0.05)', + borderRadius: borderRadius.lg, + padding: spacing.base, + borderWidth: 1, + borderColor: 'rgba(255, 255, 255, 0.08)', + }, + metaLabel: { + fontSize: typography.fontSize.xs, + color: colors.vault.textSecondary, + letterSpacing: 1, + marginBottom: spacing.xs, + fontWeight: '600', + }, + metaValue: { + fontSize: typography.fontSize.sm, + color: colors.vault.text, + fontWeight: '600', + }, + actionGroup: { + gap: spacing.sm, + }, + sectionTitle: { + fontSize: typography.fontSize.xs, + color: colors.vault.textSecondary, + letterSpacing: 1, + fontWeight: '700', + }, + actionRow: { + flexDirection: 'row', + alignItems: 'center', + gap: spacing.sm, + paddingVertical: spacing.sm, + paddingHorizontal: spacing.md, + borderRadius: borderRadius.lg, + backgroundColor: 'rgba(255, 255, 255, 0.06)', + borderWidth: 1, + borderColor: 'rgba(255, 255, 255, 0.08)', + }, + actionText: { + color: colors.vault.text, + fontSize: typography.fontSize.base, + fontWeight: '600', + }, + guardCard: { + backgroundColor: 'rgba(229, 115, 115, 0.12)', + borderRadius: borderRadius.lg, + padding: spacing.base, + gap: spacing.sm, + borderWidth: 1, + borderColor: 'rgba(229, 115, 115, 0.3)', + }, + guardHeader: { + flexDirection: 'row', + alignItems: 'center', + gap: spacing.sm, + }, + guardTitle: { + fontSize: typography.fontSize.base, + color: colors.vault.warning, + fontWeight: '700', + }, + guardText: { + fontSize: typography.fontSize.sm, + color: colors.vault.textSecondary, + lineHeight: typography.fontSize.sm * 1.5, + }, + guardButton: { + alignSelf: 'flex-start', + backgroundColor: colors.vault.warning, + paddingHorizontal: spacing.md, + paddingVertical: spacing.sm, + borderRadius: borderRadius.full, + }, + guardButtonText: { + color: colors.vault.text, + fontWeight: '700', + letterSpacing: 0.6, + }, + previewCard: { + backgroundColor: colors.vault.cardBackground, + borderRadius: borderRadius.lg, + padding: spacing.base, + borderWidth: 1, + borderColor: colors.vault.cardBorder, + }, + previewLabel: { + fontSize: typography.fontSize.xs, + color: colors.vault.textSecondary, + letterSpacing: 1, + marginBottom: spacing.xs, + fontWeight: '600', + }, + previewValue: { + fontFamily: typography.fontFamily.mono, + color: colors.vault.text, + fontSize: typography.fontSize.base, + letterSpacing: 0.6, + }, + warningCard: { + flexDirection: 'row', + alignItems: 'flex-start', + gap: spacing.sm, + backgroundColor: 'rgba(26, 58, 74, 0.6)', + borderRadius: borderRadius.lg, + padding: spacing.base, + borderWidth: 1, + borderColor: 'rgba(229, 115, 115, 0.35)', + }, + warningText: { + flex: 1, + color: colors.vault.textSecondary, + fontSize: typography.fontSize.sm, + lineHeight: typography.fontSize.sm * 1.5, + }, }); diff --git a/src/types/index.ts b/src/types/index.ts index cf2bfe2..4de19da 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -54,6 +54,7 @@ export interface Heir { id: string; name: string; email: string; + phone?: string; status: HeirStatus; releaseLevel: number; // 1-3 releaseOrder: number;