diff --git a/apps/client/package.json b/apps/client/package.json index 5b71d06..4d05a1b 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -51,6 +51,7 @@ "react-dom": "19.2.0", "react-hook-form": "^7.65.0", "react-i18next": "^16.1.0", + "react-qr-code": "^2.0.18", "simplebar-core": "^1.3.2", "simplebar-react": "^3.3.2", "stylis": "^4.3.6", @@ -74,6 +75,7 @@ "eslint-plugin-react-refresh": "^0.4.24", "globals": "^16.4.0", "prettier": "^3.6.2", + "react-dropzone": "^14.3.8", "typescript": "^5.9.3" }, "overrides": { diff --git a/apps/client/public/assets/images/avatar/avatar_5.webp b/apps/client/public/assets/images/avatar/avatar_5.webp new file mode 100644 index 0000000..040b211 Binary files /dev/null and b/apps/client/public/assets/images/avatar/avatar_5.webp differ diff --git a/apps/client/public/assets/images/logo/harvard_logo.webp b/apps/client/public/assets/images/logo/harvard_logo.webp new file mode 100644 index 0000000..ad2b760 Binary files /dev/null and b/apps/client/public/assets/images/logo/harvard_logo.webp differ diff --git a/apps/client/public/assets/images/logo/mailbluster_logo.webp b/apps/client/public/assets/images/logo/mailbluster_logo.webp new file mode 100644 index 0000000..4661087 Binary files /dev/null and b/apps/client/public/assets/images/logo/mailbluster_logo.webp differ diff --git a/apps/client/public/assets/images/logo/ndc_logo.webp b/apps/client/public/assets/images/logo/ndc_logo.webp new file mode 100644 index 0000000..0df30fd Binary files /dev/null and b/apps/client/public/assets/images/logo/ndc_logo.webp differ diff --git a/apps/client/public/assets/images/logo/technext_logo.webp b/apps/client/public/assets/images/logo/technext_logo.webp new file mode 100644 index 0000000..984e8c0 Binary files /dev/null and b/apps/client/public/assets/images/logo/technext_logo.webp differ diff --git a/apps/client/public/assets/images/logo/themewagon_logo.webp b/apps/client/public/assets/images/logo/themewagon_logo.webp new file mode 100644 index 0000000..1937070 Binary files /dev/null and b/apps/client/public/assets/images/logo/themewagon_logo.webp differ diff --git a/apps/client/public/assets/images/sections/accounts-page/accessibility/blue-tick.webp b/apps/client/public/assets/images/sections/accounts-page/accessibility/blue-tick.webp new file mode 100644 index 0000000..c26e418 Binary files /dev/null and b/apps/client/public/assets/images/sections/accounts-page/accessibility/blue-tick.webp differ diff --git a/apps/client/public/assets/images/sections/accounts-page/accessibility/color-donut.webp b/apps/client/public/assets/images/sections/accounts-page/accessibility/color-donut.webp new file mode 100644 index 0000000..996cc0c Binary files /dev/null and b/apps/client/public/assets/images/sections/accounts-page/accessibility/color-donut.webp differ diff --git a/apps/client/public/assets/images/sections/accounts-page/accessibility/unsplash-wall-paint.webp b/apps/client/public/assets/images/sections/accounts-page/accessibility/unsplash-wall-paint.webp new file mode 100644 index 0000000..f82bf18 Binary files /dev/null and b/apps/client/public/assets/images/sections/accounts-page/accessibility/unsplash-wall-paint.webp differ diff --git a/apps/client/public/assets/images/sections/accounts-page/audio-video/camera.webp b/apps/client/public/assets/images/sections/accounts-page/audio-video/camera.webp new file mode 100644 index 0000000..e4c265a Binary files /dev/null and b/apps/client/public/assets/images/sections/accounts-page/audio-video/camera.webp differ diff --git a/apps/client/public/assets/images/sections/accounts-page/credit-cards/american_express_icon.webp b/apps/client/public/assets/images/sections/accounts-page/credit-cards/american_express_icon.webp new file mode 100644 index 0000000..3ac3ac5 Binary files /dev/null and b/apps/client/public/assets/images/sections/accounts-page/credit-cards/american_express_icon.webp differ diff --git a/apps/client/public/assets/images/sections/accounts-page/credit-cards/mastercard_icon.webp b/apps/client/public/assets/images/sections/accounts-page/credit-cards/mastercard_icon.webp new file mode 100644 index 0000000..7338b4b Binary files /dev/null and b/apps/client/public/assets/images/sections/accounts-page/credit-cards/mastercard_icon.webp differ diff --git a/apps/client/public/assets/images/sections/accounts-page/credit-cards/visa_icon.webp b/apps/client/public/assets/images/sections/accounts-page/credit-cards/visa_icon.webp new file mode 100644 index 0000000..1cdfc01 Binary files /dev/null and b/apps/client/public/assets/images/sections/accounts-page/credit-cards/visa_icon.webp differ diff --git a/apps/client/public/assets/images/sections/accounts-page/privacy-protection/qr-code.webp b/apps/client/public/assets/images/sections/accounts-page/privacy-protection/qr-code.webp new file mode 100644 index 0000000..d8a600a Binary files /dev/null and b/apps/client/public/assets/images/sections/accounts-page/privacy-protection/qr-code.webp differ diff --git a/apps/client/public/assets/images/sections/misc/faq-dark.webp b/apps/client/public/assets/images/sections/misc/faq-dark.webp new file mode 100644 index 0000000..444b8ea Binary files /dev/null and b/apps/client/public/assets/images/sections/misc/faq-dark.webp differ diff --git a/apps/client/public/assets/images/sections/misc/faq-light.webp b/apps/client/public/assets/images/sections/misc/faq-light.webp new file mode 100644 index 0000000..9d07c41 Binary files /dev/null and b/apps/client/public/assets/images/sections/misc/faq-light.webp differ diff --git a/apps/client/public/assets/images/sections/sidebar-vibrant.webp b/apps/client/public/assets/images/sections/sidebar-vibrant.webp new file mode 100644 index 0000000..d088fdf Binary files /dev/null and b/apps/client/public/assets/images/sections/sidebar-vibrant.webp differ diff --git a/apps/client/public/assets/images/sections/topbar-vibrant.webp b/apps/client/public/assets/images/sections/topbar-vibrant.webp new file mode 100644 index 0000000..290cf8e Binary files /dev/null and b/apps/client/public/assets/images/sections/topbar-vibrant.webp differ diff --git a/apps/client/public/assets/json/bird_dark.json b/apps/client/public/assets/json/bird_dark.json new file mode 100644 index 0000000..d953592 --- /dev/null +++ b/apps/client/public/assets/json/bird_dark.json @@ -0,0 +1,1679 @@ +{ + "v": "5.12.1", + "fr": 23.976, + "ip": 0, + "op": 144, + "w": 226, + "h": 250, + "nm": "Bird_Dark", + "assets": [ + { + "id": "image_0", + "w": 223, + "h": 350, + "u": "", + "p": "data:image/webp;base64,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", + "e": 1 + }, + { + "id": "image_1", + "w": 40, + "h": 60, + "u": "", + "p": "data:image/webp;base64,UklGRjQCAABXRUJQVlA4WAoAAAAQAAAAJwAAOwAAQUxQSAQBAAABgBDZbt1KEATBEAzBEAJBEAzBEAJBEArBEALBEMRAfR/Lui2BiJgA+vrWx5ACq2r+7xIIq0efktfM41azxI+t5IgnPiniqSNBPLkcNc++T6qlrQN+PL/G1IE91B05ItWhM8DrU4ZjdccGGjtx8LW7UXU3UbS/QTMgoBFgw7QAdYhRWBEao2vlyUHRNONQUc9XinZzYIuoIxft+XGoBNShi/bi2LFjwxjvhmMH7Q1jvBPH3rR/gUrAMDftq0ONA4IZFBwQ44hChKIT8dCntNgLoBQfecafctFhS3vRKWcZH9GT1Ohccjplrgyl1JqglCxHSumXxToBiwZmIWzpc7nPu9DXA1ZQOCAKAQAA0AYAnQEqKAA8AD5tMpJHJCMhoSq0DACADYloALszcfpHsnHe8VbgG2A5530PbwBvKgGjYO2IBmuXlDGoxVAgAP75m3//LkyhOlo3gXovCSXfuzEAr77g4uU5X0IXXfCrjbnLlbEJBSV38DtqPzySwJJtLa5OTavXSHkALKGY9ywXKq2rhs3QvvAYdK383/nlOnv/TY0I0FagDGx1/ZvDrYWXbgb05czmwFRe2y0WgturafRP+HfoTKqznU6EQWxR/e68X/HD0QZW3Iqn9gevv69//5i3VMQM8o0yb3gGSau14bd/vgWOsGSBp8Y8/dF9Az891+z4t5RLo9RxhLkEytB5JvzS27wAAAA=", + "e": 1 + }, + { + "id": "image_2", + "w": 342, + "h": 334, + "u": "", + "p": "data:image/webp;base64,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", + "e": 1 + }, + { + "id": "image_3", + "w": 77, + "h": 96, + "u": "", + "p": "data:image/webp;base64,UklGRkoEAABXRUJQVlA4WAoAAAAQAAAATAAAXwAAQUxQSKIBAAABkFXbTmRBV0IkIAEJSEACPQgoCUh4EpCABCQgAQlxQA9UFSTp4TMiJgD/pUMIMd9eIYSgJFy59bmXW/vkGEgKxU+fIlvN0R9yV5/Ce83R76HUp9bqX7nCUzG7Z65M5dcTKlN9fnDx1B9vXJsGdqwTTwMbLahM/d+Dx5L61N9wP6aB4S5NAzvuqwXJlIGH0YD0BF0d0yOq2jJeFl1Mb5BUffA+aXIb4FlNwVbPWtwe+KGjYjd1FWEbqCtoOEhdXjwB6tIGzlIXlg7Bs6iB454lXefgBTEJQJKTITJLYZKBKqRAKHUZTgo8SyiQmyR4QajnGiQTHwuiEE81CK+HkjTiIwPiryNJHsYBhsJ4IGtA28akImzL0Nl2OSVpU4HWscepyVsK1LotQQ/qhgbFaUPQRO8GVPdXSVd+M6A7vEnK8IJJW3uWob08YlKXH32gPjxy+vyTAgOfOFMaTAmmNJjYb6INc80wpdqSbYk2hJtgQ7zxNuQb2FhXw4ixaja4uc42XDfBhnoDE2mumw3p5rIh3zgbrlWDjcS/sTcCVFqvHv+AVlA4IIICAADQEACdASpNAGAAPm0skkYkIqGhLvN8+IANiWQGKAQID8AP0A/gCLCGP+gawT3r8lcTu4D5T50G2A8wH65etn6E94Z9ADy1vZRyI/wAxQRfO6lU3xkrd/MrQHfkkE8Tp4j0EUplVrpsTA4U96FmH/1kUb+eZxe/IUiyT5jUs/uymdTcuiIcjGYcGqIGI500KAD9Mf//7f6Z/2Y0kgeCbvAG4RvIy6j1uVYnEIqbrOg90kYfvp7WIyhxKGhXx890hZiIEes9tVWy9DksF23HfHgeECcZs4dRdWdge7YLzG5VjQ+ixbpmln6fSFCDxvXPOOZW0RuyetVtj8F6vzIAwcMY/OflEPjR3/9q8vrep4T27mkjrrO92jGZlCnf+gOWqkRVcX/PCMY25aYPLUvWlLVUNGee0BuUs7Mh3JSfi47HbpLbUrLmqchpWWeY65940uQOT6QOlutWvUPWAT4WI7jRG0IIq91j2+bcQrY7uFySvR+phtlbX9BSaoQKzdLId9qTu9e/LsAnLftu7/PLL0XRcFbk1GK/RYv7t74Oe+xgY0eItEBPeDa5f/70ef/+9WrN9Q/2M4o9lCPFZ5I6QlUEYEnfNGeB90IHcPRGQrHiPqtwBTXl3tBc+DZbQHVC6/aqVSMb1p9rgVYv7t74qEM9fctEI2zZA3/1p+4uZ//9v6ZicvJY8Alwid490xl0aDrJaJHRqYugjZU774U8hLLIlKHJPWJT/siowwAfnvNKVdJ2J9Fg66fZo52dCGeAo9+VJVp/H3pC1avsqSxrQFBzwddut+I/74lXDbF6fmklLF9kI3AQrK5lz4huCjcAJjx1dYxyzXYJP/+9Hn//vVQAAAA=", + "e": 1 + }, + { + "id": "image_4", + "w": 117, + "h": 135, + "u": "", + "p": "data:image/webp;base64,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", + "e": 1 + }, + { + "id": "image_5", + "w": 113, + "h": 362, + "u": "", + "p": "data:image/webp;base64,UklGRmAKAABXRUJQVlA4WAoAAAAQAAAAcAAAaQEAQUxQSCkEAAABoBTZdiSLEQRBEAQRcIQgCILWXhWEB0EQBKEgPAAeCoAHQRAARzwP/Qe9ure7vYuICQjOU1dVESklkEzLPrm0t4Rv2JfX2RI2/dp/r57ZmNk8Eir5NjM7C6Yf/tpgNhugvGzzbGjysv2zQsnLXGrCkZd5FRR5mV+NEPIyzysDyMt8r3q7vMx9uVle5n/lW9Vld5zxRs1u2u/T7LbpLs3uO27S7M7xFs1u3e7Q7N7jBs1ufvlrdnt3zdg0Y9OMTTOEl5dUYgjNIKqPqGbWfzQiw5DKtnguWz9RGQa37sqGt+wqgMLuhmdtEzy6beDp2xTPsW3iKdsMb9id8KxtBY9uq3j6NsFz8CnbTjxxm8KZYfsFR/cZXOHTtiU8eVvBE+j8tq/BsbpN8Jx8bFvno3gWH30+Jh7ZZi9AeToioLSrAAp0Fh99gfo2wSN8Dj7lBYp8wvPR4Vz7FI6+QPKOKu+oyCe8PouPvqMGH3lHHXzKe+5EEx0ImvB/0OSj74HKp7xd5D0Q+YT/hy4+iqXyKc/J4CPvqManvKMin/AKLT76jpJ3VOVTXqDIJ7xCF5LmRJHIsyIv0MGnvECRT0DS+agXfYEGH3mBCpDFx7wkPoHQ4qNAEp/ipfMRPo1PAXLwES/hFbpwnG4Uh7rpfIRPw2FuCp/MJwBJfIobfeKqG8Ehz0vF0d0UHOom8gk4Lj8ThvlRPgNHciM4ipuDT8EhbjKfgKP7WTDUjz5v5keeuOSm4Ch8qpuAQ56YC4b6UT4dxvIjMMxPxZHdFBzFTcJxuAk4xM+EcfpRGOrnhLH8CAzzc+DIbgqO4ibjEDcBR+ejfhTG5GN+Oo7sRnAUNxWHuCk4upuEQ90EHNPPgmF+FEfhU90IDuFzuqk4LjcFh7lJQLKXAKS6WTjEjeI4+VxuBIcRyl4qkOqlABEvGcjpJQCZfMzNBaR4USCHlxNI9yJAlI95qUiyk4KkOclIxElAonyWlwnEkhNFUvmIk45EnQiSxceSjwKl8ek+MhT1EaAYoczn8KFQBp+Lj0UXgqXwET7qomIxFwVM5nN4yGCGhwBm8rHEp3mYYIYHBTP5WOLTHAw0w4GgmXws8Wl8xr4CZ/KxzOfgc/JZ2yIey7sCoIOP8jFClU/fdQGauxSQJT4Hn5OPEap8Op/Jx9KWiantSIZ57Oig5oZmqNN3xW6w2/dEWYZbviG106DrV1K/DP0XihrB9ZmkxvETdRmZZiz1g2Zs8uIhj9R41gfFeK7w8CTSHxnPFR8kIkd4WHiM8DjTGOHjRaKHTw4Kq4bPxkmgx/D5dKEbKXy9KrA1UvjeNBamecTw/bFdeEYJu/NYSK4Wg8s6FobrSMFx7fNu55GC+3Sc6y5Xr+G2+RiXN5Uaw+3L0XV5mCotB6CxVOmq8zsuPUVKDshz+WQM70oAVlA4IBAGAABwMACdASpxAGoBPm00lUakIyIhKfVbAIANiWVu/DGvEbYDYRfT4MdwvybzrP8h6Q/QQ8YD1Uv9l6vP1p6nH1Qv6L6jH7X9ax+72VA+bfsg/QDy4x3YyKLPrdvZee2lu/TOihK8w/fQ5UWwFofu7NWGvssq82Z8radOTZJYxV6UxN/TNLvuctgqbGEZjL6jLY4NjeWhZtOecoJKotmh04r+x7/EyvbEM2BXE9TxqWx9azLaK9vYmcvm3bfMHsElLhUZJokVHzQf5dgaLARLhi+Sy/WqVJrnN7ud28cQjadAbxt2hp09Qrcltxc7i2CovT9a9U2mFCK/dRLV9tnzW5bfg0vXJzPfdK4PLKlJwVrm4VNFqT5mMLyPftRYlVHina3EzEA2nDxtTwvZ7m7lMWnqs4m1MOhYxnO7XXX9KlOSlmYkDJDBwiehHszmd45s0HmEZbUTvPUNDaX8BESq36+QLhKKDJqzF6dLbIHDb5zEvU7lE9A7OOgfLraaxrwb/R4DWRWJZxObgQQjceAA/vz4c8znvOs/4y3fqb+b8sO+djKDx+w5Fy4b8er0XLx+1r/xs1Zu8ZLME+VK0Y29gB/6udJR5Z/Kv4s/VgX//y9J0v/IjCynmUeLFQeQeyH4ZL/q5vCMSCWOKzcQLIbTaVGWqSKy75A2/OxlB4w3+e2lJX5d33sjJ1xWZ8+lA2kzldIe87TMPGv9Nqw46IT2MZv/RfugHD70ur1ho4kLygjYNjluTWSENS8Kd7xEjLpnIGwYv2yYWUq7XEy7m2kxKXBpvbtgxM646o81DbZA8ps273cSL3XM7fW3LDAf1hIv1b4DbKaAJehLG31Ldgz1T0sce0shCPXV3sr26uWO27hUw9ocaOtmc5+hwphch5W4bkfbSw7U/2HSv7geVQwT64kZ18EO5RWXDh7QAkyrpzyLrEe/ZU0lEgn9qQv/EO/PFWHGsaYjKD04eduZgYaCQGI6BNRixSoY+d0UJal7TAfgwrVtIHMgDJ23zDJw8lL24PbpsPUHSmlXEjl5UFolQzO8fDqo2M/2foTkoUGpL9/7EqZDvHU2tpQdXuz/+1e/2wWjB1pTZPFUmuEhtliYZZAmmdb7qwSfO2uJrbU/uSagxCInkIqdBuSPLG1nMoe5owHGG+I3jFV1xGGh+Y0ctm4yyUtRdDK45chv//6RTGY0ZVql9gtiWvKrRJLlb2POH7fVTCnkQU11m9R2Mj5KmKfeSXO0XgKnYlassYw60MeAirZE0A2bV2vaj/LFQIF0vJ+zkBokxQGyQVsounlm4tmLbbmZZI9Ron/RFM3OCviV3d+rNQ2luJXzdL2vNvWPT696WrpAwo0R2UltCHNfm6lalTdqXpi/9fvuZGTq1SkrC9mA8Wesk0LTrcNf2U7ZHIaYSYp9GL/fqEiwrX700H89tHvxHhdL9mqm8qrzuTXlpwO8yRA95pmZBIrHnrhRU9JCFW2A3lxe1fMe9Rl/s2H+pgXls/kCELzby5oDbeb2TDJ7Ta9aSzzNfZDUsxnQqN6qCrSLORVtSUt4ch6ci5wUJJPfralB60TGlqvc+M4zQ5rY0ywj8SntabaNQAgUhiQzzYGD1r/hS/jAYY1Sq9KqpzsxRRWsrJdXZzY7Shy4OsMjtJjHAYTon7vPF1KATODxYrLgxJatGX00nssYAJAPrfAjx/NnnpwB3hK6RNgBf5gaj+v0GkB4Po5tkYKnyS///0ip3/HEsjUsggSuCnVdaU2RstAjytAy9PmjBCCl0akmF9odgzVEUYNgkLarrXxuXm5eKlZRA55RRWej6I3F3aLLOmDS7/oxO8e1jkvE/58tKyVWH3XH+ZcSSXO+4xTw7Vv0yZp2wtxnW0JUQXe6T8JmJqHnagxoQeZGfzhcJRnVgm9QZ/vEhfELFvKk9yNM0fhKBEbQzsvt00lYiRbP6iv1X5JLap8TY6bZ4FAKU3FAkFw0Sr+v6eNy425cp7nVhjocIdcv7qqogwlNHHOhsqLfnlq0zgVKMecqzmxUIM+j+S71swg8fgD/gx//9hr//r+X//2BYAI//FpoAAAA", + "e": 1 + }, + { + "id": "image_6", + "w": 115, + "h": 354, + "u": "", + "p": "data:image/webp;base64,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", + "e": 1 + }, + { + "id": "image_7", + "w": 156, + "h": 271, + "u": "", + "p": "data:image/webp;base64,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", + "e": 1 + }, + { + "id": "comp_0", + "nm": "Bird Comp_Export_Dark", + "fr": 23.976, + "layers": [ + { + "ind": 1, + "ty": 0, + "nm": "Bird Comp_Dark", + "refId": "comp_1", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100 }, + "r": { "a": 0, "k": 0 }, + "p": { "a": 0, "k": [450, 489, 0], "l": 2 }, + "a": { "a": 0, "k": [450, 489, 0], "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "l": 2 } + }, + "ao": 0, + "w": 900, + "h": 978, + "ip": 0, + "op": 144, + "st": 0 + } + ] + }, + { + "id": "comp_1", + "nm": "Bird Comp_Dark", + "fr": 23.976, + "layers": [ + { + "ind": 1, + "ty": 4, + "nm": "Shape Layer 4", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100 }, + "r": { "a": 0, "k": 0 }, + "p": { "a": 0, "k": [450, 489, 0], "l": 2 }, + "a": { "a": 0, "k": [0, 0, 0], "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "l": 2 } + }, + "ao": 0, + "shapes": [], + "ip": 0, + "op": 144, + "st": 0, + "ct": 1 + }, + { + "ind": 2, + "ty": 4, + "nm": "Shape Layer 3", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100 }, + "r": { "a": 0, "k": 104 }, + "p": { "a": 0, "k": [620.371, 195.863, 0], "l": 2 }, + "a": { "a": 0, "k": [-103.478, -258.572, 0], "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "l": 2 } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "a": 0, + "k": { + "i": [ + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0] + ], + "v": [ + [-108.755, -265.608], + [-179.115, -332.45] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "st", + "c": { "a": 0, "k": [0.776, 0.867, 0.984, 1] }, + "o": { "a": 0, "k": 100 }, + "w": { "a": 0, "k": 4 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "fl", + "c": { "a": 0, "k": [1, 1, 1, 1] }, + "o": { "a": 0, "k": 100 }, + "r": 1, + "nm": "Fill 1" + }, + { + "ty": "tr", + "p": { "a": 0, "k": [0, 0] }, + "a": { "a": 0, "k": [0, 0] }, + "s": { "a": 0, "k": [100, 100] }, + "r": { "a": 0, "k": 0 }, + "o": { "a": 0, "k": 100 }, + "sk": { "a": 0, "k": 0 }, + "sa": { "a": 0, "k": 0 }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + }, + { + "ty": "tm", + "s": { + "a": 1, + "k": [ + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 57, + "s": [0] + }, + { "t": 60, "s": [100] } + ] + }, + "e": { + "a": 1, + "k": [ + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 54, + "s": [0] + }, + { "t": 57.667, "s": [100] } + ] + }, + "o": { "a": 0, "k": 0 }, + "m": 1, + "nm": "Trim Paths 1" + } + ], + "ip": 0, + "op": 144, + "st": 0, + "ct": 1 + }, + { + "ind": 3, + "ty": 4, + "nm": "Shape Layer 2", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100 }, + "r": { "a": 0, "k": 87 }, + "p": { "a": 0, "k": [599.371, 173.863, 0], "l": 2 }, + "a": { "a": 0, "k": [-103.478, -258.572, 0], "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "l": 2 } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "a": 0, + "k": { + "i": [ + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0] + ], + "v": [ + [-108.755, -265.608], + [-179.115, -332.45] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "st", + "c": { "a": 0, "k": [0.776, 0.867, 0.984, 1] }, + "o": { "a": 0, "k": 100 }, + "w": { "a": 0, "k": 4 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "fl", + "c": { "a": 0, "k": [1, 1, 1, 1] }, + "o": { "a": 0, "k": 100 }, + "r": 1, + "nm": "Fill 1" + }, + { + "ty": "tr", + "p": { "a": 0, "k": [0, 0] }, + "a": { "a": 0, "k": [0, 0] }, + "s": { "a": 0, "k": [100, 100] }, + "r": { "a": 0, "k": 0 }, + "o": { "a": 0, "k": 100 }, + "sk": { "a": 0, "k": 0 }, + "sa": { "a": 0, "k": 0 }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + }, + { + "ty": "tm", + "s": { + "a": 1, + "k": [ + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 57, + "s": [0] + }, + { "t": 60, "s": [100] } + ] + }, + "e": { + "a": 1, + "k": [ + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 54, + "s": [0] + }, + { "t": 57.667, "s": [100] } + ] + }, + "o": { "a": 0, "k": 0 }, + "m": 1, + "nm": "Trim Paths 1" + } + ], + "ip": 0, + "op": 144, + "st": 0, + "ct": 1 + }, + { + "ind": 4, + "ty": 4, + "nm": "Shape Layer 1", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100 }, + "r": { "a": 0, "k": 71 }, + "p": { "a": 0, "k": [568.155, 160.068, 0], "l": 2 }, + "a": { "a": 0, "k": [-103.478, -258.572, 0], "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "l": 2 } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "a": 0, + "k": { + "i": [ + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0] + ], + "v": [ + [-108.755, -265.608], + [-179.115, -332.45] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "st", + "c": { "a": 0, "k": [0.776, 0.867, 0.984, 1] }, + "o": { "a": 0, "k": 100 }, + "w": { "a": 0, "k": 4 }, + "lc": 2, + "lj": 1, + "ml": 4, + "nm": "Stroke 1" + }, + { + "ty": "fl", + "c": { "a": 0, "k": [1, 1, 1, 1] }, + "o": { "a": 0, "k": 100 }, + "r": 1, + "nm": "Fill 1" + }, + { + "ty": "tr", + "p": { "a": 0, "k": [0, 0] }, + "a": { "a": 0, "k": [0, 0] }, + "s": { "a": 0, "k": [100, 100] }, + "r": { "a": 0, "k": 0 }, + "o": { "a": 0, "k": 100 }, + "sk": { "a": 0, "k": 0 }, + "sa": { "a": 0, "k": 0 }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + }, + { + "ty": "tm", + "s": { + "a": 1, + "k": [ + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 57, + "s": [0] + }, + { "t": 60, "s": [100] } + ] + }, + "e": { + "a": 1, + "k": [ + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 54, + "s": [0] + }, + { "t": 57.667, "s": [100] } + ] + }, + "o": { "a": 0, "k": 0 }, + "m": 1, + "nm": "Trim Paths 1" + } + ], + "ip": 0, + "op": 144, + "st": 0, + "ct": 1 + }, + { + "ind": 5, + "ty": 2, + "nm": "Left Wing", + "parent": 10, + "refId": "image_0", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100 }, + "r": { + "a": 1, + "k": [ + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.333], "y": [0] }, + "t": 0, + "s": [0] + }, + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.333], "y": [0] }, + "t": 13, + "s": [0] + }, + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.333], "y": [0] }, + "t": 17, + "s": [-18] + }, + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.333], "y": [0] }, + "t": 31, + "s": [-18] + }, + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 35, + "s": [11] + }, + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 43, + "s": [11] + }, + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 46, + "s": [-18] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 53, + "s": [-18] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 61, + "s": [26] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 64, + "s": [11] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 67, + "s": [26] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 70, + "s": [11] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 73, + "s": [26] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 76, + "s": [11] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 88, + "s": [11] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 100.745, + "s": [-122] + }, + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 122.223, + "s": [-122] + }, + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.333], "y": [0] }, + "t": 136, + "s": [0] + }, + { "t": 144, "s": [0] } + ] + }, + "p": { "a": 0, "k": [62.251, 226.268, 0], "l": 2 }, + "a": { "a": 0, "k": [205.076, 292.705, 0], "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "l": 2 } + }, + "ao": 0, + "ef": [ + { + "ty": 21, + "nm": "Fill", + "np": 9, + "en": 1, + "ef": [ + { "ty": 10, "nm": "Fill Mask", "v": { "a": 0, "k": 0 } }, + { "ty": 7, "nm": "All Masks", "v": { "a": 0, "k": 0 } }, + { "ty": 2, "nm": "Color", "v": { "a": 0, "k": [0.11, 0.286, 0.518, 1] } }, + { "ty": 7, "nm": "Invert", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Horizontal Feather", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Vertical Feather", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Opacity", "v": { "a": 0, "k": 1 } } + ] + } + ], + "ip": 0, + "op": 144, + "st": 0 + }, + { + "ind": 6, + "ty": 4, + "nm": "Shape Layer 5", + "parent": 5, + "tt": 1, + "tp": 10, + "sr": 1, + "ks": { + "o": { "a": 0, "k": 41 }, + "r": { "a": 0, "k": -3 }, + "p": { "a": 0, "k": [318.686, 327.323, 0], "l": 2 }, + "a": { "a": 0, "k": [0, 0, 0], "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "l": 2 } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "a": 0, + "k": { + "i": [ + [0, 0], + [0, 0], + [-86.937, -26.603], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0], + [26.09, 7.983], + [0, 0], + [0, 0] + ], + "v": [ + [-213, -158], + [-280.921, -78.443], + [-163.806, 8.204], + [-110, 14], + [-98.75, -84] + ], + "c": true + } + }, + "nm": "Path 1" + }, + { + "ty": "fl", + "c": { "a": 0, "k": [0.078, 0.208, 0.376, 1] }, + "o": { "a": 0, "k": 100 }, + "r": 1, + "nm": "Fill 1" + }, + { + "ty": "tr", + "p": { "a": 0, "k": [0, 0] }, + "a": { "a": 0, "k": [0, 0] }, + "s": { "a": 0, "k": [100, 100] }, + "r": { "a": 0, "k": 0 }, + "o": { "a": 0, "k": 100 }, + "sk": { "a": 0, "k": 0 }, + "sa": { "a": 0, "k": 0 }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 0, + "op": 144, + "st": 0, + "ct": 1 + }, + { + "ind": 7, + "ty": 2, + "nm": "Eye", + "parent": 10, + "refId": "image_1", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100 }, + "r": { "a": 0, "k": 22 }, + "p": { "a": 0, "k": [116.077, 89.268, 0], "l": 2 }, + "a": { "a": 0, "k": [19.501, 29.596, 0], "l": 2 }, + "s": { + "a": 1, + "k": [ + { + "i": { "x": [0.571, 0.571, 0.571], "y": [1, 1, 1] }, + "o": { "x": [0.191, 0.191, 0.191], "y": [0, 0, 0] }, + "t": 0, + "s": [100, 100, 100] + }, + { + "i": { "x": [0.664, 0.664, 0.664], "y": [1, 1, 1] }, + "o": { "x": [0.331, 0.331, 0.331], "y": [0, 0, 0] }, + "t": 20, + "s": [100, 100, 100] + }, + { + "i": { "x": [0.571, 0.571, 0.571], "y": [1, 1, 1] }, + "o": { "x": [0.338, 0.338, 0.338], "y": [0, 0, 0] }, + "t": 22.5, + "s": [100, 10, 100] + }, + { + "i": { "x": [0.704, 0.704, 0.704], "y": [1, 1, 1] }, + "o": { "x": [0.331, 0.331, 0.331], "y": [0, 0, 0] }, + "t": 25, + "s": [100, 100, 100] + }, + { + "i": { "x": [0.667, 0.667, 0.667], "y": [1, 1, 1] }, + "o": { "x": [0.333, 0.333, 0.333], "y": [0, 0, 0] }, + "t": 46, + "s": [100, 100, 100] + }, + { + "i": { "x": [0.667, 0.667, 0.667], "y": [1, 1, 1] }, + "o": { "x": [0.333, 0.333, 0.333], "y": [0, 0, 0] }, + "t": 49, + "s": [100, 10, 100] + }, + { + "i": { "x": [0.667, 0.667, 0.667], "y": [1, 1, 1] }, + "o": { "x": [0.333, 0.333, 0.333], "y": [0, 0, 0] }, + "t": 55, + "s": [100, 130, 100] + }, + { + "i": { "x": [0.833, 0.833, 0.833], "y": [1, 1, 1] }, + "o": { "x": [0.333, 0.333, 0.333], "y": [0, 0, 0] }, + "t": 58, + "s": [100, 100, 100] + }, + { + "i": { "x": [0.833, 0.833, 0.833], "y": [1, 1, 1] }, + "o": { "x": [0.167, 0.167, 0.167], "y": [0, 0, 0] }, + "t": 89, + "s": [100, 100, 100] + }, + { + "i": { "x": [0.833, 0.833, 0.833], "y": [1, 1, 1] }, + "o": { "x": [0.167, 0.167, 0.167], "y": [0, 0, 0] }, + "t": 100.745, + "s": [100, 10, 100] + }, + { + "i": { "x": [0.833, 0.833, 0.833], "y": [1, 1, 1] }, + "o": { "x": [0.167, 0.167, 0.167], "y": [0, 0, 0] }, + "t": 120.001, + "s": [100, 10, 100] + }, + { + "i": { "x": [0.833, 0.833, 0.833], "y": [1, 1, 1] }, + "o": { "x": [0.167, 0.167, 0.167], "y": [0, 0, 0] }, + "t": 123.334, + "s": [100, 100, 100] + }, + { "t": 144, "s": [100, 100, 100] } + ], + "l": 2 + } + }, + "ao": 0, + "ef": [ + { + "ty": 35, + "nm": "Transform", + "np": 14, + "en": 1, + "ef": [ + { "ty": 3, "nm": "Anchor Point", "v": { "a": 0, "k": [20, 30] } }, + { "ty": 3, "nm": "Position", "v": { "a": 0, "k": [20, 30] } }, + { "ty": 7, "nm": "Uniform Scale", "v": { "a": 0, "k": 1 } }, + { "ty": 0, "nm": "Scale", "v": { "a": 0, "k": 100 } }, + { "ty": 0, "nm": " ", "v": { "a": 0, "k": 100 } }, + { "ty": 0, "nm": "Skew", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Skew Axis", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Rotation", "v": { "a": 0, "k": -22 } }, + { "ty": 0, "nm": "Opacity", "v": { "a": 0, "k": 100 } }, + { "ty": 7, "nm": "Use Composition’s Shutter Angle", "v": { "a": 0, "k": 1 } }, + { "ty": 0, "nm": "Shutter Angle", "v": { "a": 0, "k": 0 } }, + { "ty": 7, "nm": "Sampling", "v": { "a": 0, "k": 1 } } + ] + }, + { + "ty": 21, + "nm": "Fill", + "np": 9, + "en": 1, + "ef": [ + { "ty": 10, "nm": "Fill Mask", "v": { "a": 0, "k": 0 } }, + { "ty": 7, "nm": "All Masks", "v": { "a": 0, "k": 0 } }, + { "ty": 2, "nm": "Color", "v": { "a": 0, "k": [0.039, 0.106, 0.188, 1] } }, + { "ty": 7, "nm": "Invert", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Horizontal Feather", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Vertical Feather", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Opacity", "v": { "a": 0, "k": 1 } } + ] + } + ], + "ip": 0, + "op": 144, + "st": 0 + }, + { + "ind": 8, + "ty": 3, + "nm": "Null 4", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 0 }, + "r": { "a": 0, "k": 0 }, + "p": { "a": 0, "k": [450, 489, 0], "l": 2 }, + "a": { "a": 0, "k": [0, 0, 0], "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "l": 2 } + }, + "ao": 0, + "ip": 0, + "op": 144, + "st": 0 + }, + { + "ind": 9, + "ty": 2, + "nm": "Head 2", + "parent": 8, + "refId": "image_2", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100 }, + "r": { + "a": 1, + "k": [ + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 0, + "s": [3] + }, + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.333], "y": [0] }, + "t": 46, + "s": [3] + }, + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.333], "y": [0] }, + "t": 50, + "s": [-5] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 54, + "s": [3] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 87, + "s": [3] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 100.745, + "s": [-19] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 118.334, + "s": [-19] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 133, + "s": [3] + }, + { "t": 144, "s": [3] } + ] + }, + "p": { + "a": 1, + "k": [ + { + "i": { "x": 0.667, "y": 0.667 }, + "o": { "x": 0.333, "y": 0.333 }, + "t": 0, + "s": [33.251, -50.307, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": { "x": 0.667, "y": 1 }, + "o": { "x": 0.333, "y": 0 }, + "t": 46, + "s": [33.251, -50.307, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": { "x": 0.667, "y": 1 }, + "o": { "x": 0.333, "y": 0 }, + "t": 49, + "s": [33.251, -34.307, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": { "x": 0.667, "y": 1 }, + "o": { "x": 0.333, "y": 0 }, + "t": 55, + "s": [33.251, -64.973, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": { "x": 0.667, "y": 0.667 }, + "o": { "x": 0.167, "y": 0.167 }, + "t": 59, + "s": [33.251, -50.307, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": { "x": 0.667, "y": 1 }, + "o": { "x": 0.167, "y": 0 }, + "t": 88, + "s": [33.251, -50.307, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": { "x": 0.667, "y": 0.667 }, + "o": { "x": 0.167, "y": 0.167 }, + "t": 100, + "s": [33.251, -25.307, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": { "x": 0.667, "y": 1 }, + "o": { "x": 0.167, "y": 0 }, + "t": 117.779, + "s": [33.251, -25.307, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": { "x": 0.667, "y": 0.667 }, + "o": { "x": 0.333, "y": 0.333 }, + "t": 133, + "s": [33.251, -50.307, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { "t": 144, "s": [33.251, -50.307, 0] } + ], + "l": 2 + }, + "a": { "a": 0, "k": [198.73, 206.751, 0], "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "l": 2 } + }, + "ao": 0, + "ef": [ + { + "ty": 21, + "nm": "Fill", + "np": 9, + "en": 1, + "ef": [ + { "ty": 10, "nm": "Fill Mask", "v": { "a": 0, "k": 0 } }, + { "ty": 7, "nm": "All Masks", "v": { "a": 0, "k": 0 } }, + { "ty": 2, "nm": "Color", "v": { "a": 0, "k": [0.11, 0.286, 0.518, 1] } }, + { "ty": 7, "nm": "Invert", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Horizontal Feather", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Vertical Feather", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Opacity", "v": { "a": 0, "k": 1 } } + ] + } + ], + "ip": 0, + "op": 144, + "st": 0 + }, + { + "ind": 10, + "ty": 2, + "nm": "Head", + "parent": 8, + "td": 1, + "refId": "image_2", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100 }, + "r": { + "a": 1, + "k": [ + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 0, + "s": [3] + }, + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.333], "y": [0] }, + "t": 46, + "s": [3] + }, + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.333], "y": [0] }, + "t": 50, + "s": [-5] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 54, + "s": [3] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 87, + "s": [3] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 100.745, + "s": [-19] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 118.334, + "s": [-19] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 133, + "s": [3] + }, + { "t": 144, "s": [3] } + ] + }, + "p": { + "a": 1, + "k": [ + { + "i": { "x": 0.667, "y": 0.667 }, + "o": { "x": 0.333, "y": 0.333 }, + "t": 0, + "s": [33.251, -50.307, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": { "x": 0.667, "y": 1 }, + "o": { "x": 0.333, "y": 0 }, + "t": 46, + "s": [33.251, -50.307, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": { "x": 0.667, "y": 1 }, + "o": { "x": 0.333, "y": 0 }, + "t": 49, + "s": [33.251, -34.307, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": { "x": 0.667, "y": 1 }, + "o": { "x": 0.333, "y": 0 }, + "t": 55, + "s": [33.251, -64.973, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": { "x": 0.667, "y": 0.667 }, + "o": { "x": 0.167, "y": 0.167 }, + "t": 59, + "s": [33.251, -50.307, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": { "x": 0.667, "y": 1 }, + "o": { "x": 0.167, "y": 0 }, + "t": 88, + "s": [33.251, -50.307, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": { "x": 0.667, "y": 0.667 }, + "o": { "x": 0.167, "y": 0.167 }, + "t": 100, + "s": [33.251, -25.307, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": { "x": 0.667, "y": 1 }, + "o": { "x": 0.167, "y": 0 }, + "t": 117.779, + "s": [33.251, -25.307, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": { "x": 0.667, "y": 0.667 }, + "o": { "x": 0.333, "y": 0.333 }, + "t": 133, + "s": [33.251, -50.307, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { "t": 144, "s": [33.251, -50.307, 0] } + ], + "l": 2 + }, + "a": { "a": 0, "k": [198.73, 206.751, 0], "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "l": 2 } + }, + "ao": 0, + "ef": [ + { + "ty": 21, + "nm": "Fill", + "np": 9, + "en": 1, + "ef": [ + { "ty": 10, "nm": "Fill Mask", "v": { "a": 0, "k": 0 } }, + { "ty": 7, "nm": "All Masks", "v": { "a": 0, "k": 0 } }, + { "ty": 2, "nm": "Color", "v": { "a": 0, "k": [0.776, 0.867, 0.984, 1] } }, + { "ty": 7, "nm": "Invert", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Horizontal Feather", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Vertical Feather", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Opacity", "v": { "a": 0, "k": 1 } } + ] + } + ], + "ip": 0, + "op": 144, + "st": 0 + }, + { + "ind": 11, + "ty": 2, + "nm": "Beak", + "parent": 10, + "refId": "image_3", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100 }, + "r": { "a": 0, "k": 0 }, + "p": { "a": 0, "k": [57.129, 110.304, 0], "l": 2 }, + "a": { "a": 0, "k": [47.283, 39.924, 0], "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "l": 2 } + }, + "ao": 0, + "ef": [ + { + "ty": 21, + "nm": "Fill", + "np": 9, + "en": 1, + "ef": [ + { "ty": 10, "nm": "Fill Mask", "v": { "a": 0, "k": 0 } }, + { "ty": 7, "nm": "All Masks", "v": { "a": 0, "k": 0 } }, + { "ty": 2, "nm": "Color", "v": { "a": 0, "k": [0.078, 0.208, 0.376, 1] } }, + { "ty": 7, "nm": "Invert", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Horizontal Feather", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Vertical Feather", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Opacity", "v": { "a": 0, "k": 1 } } + ] + } + ], + "ip": 0, + "op": 144, + "st": 0 + }, + { + "ind": 12, + "ty": 4, + "nm": "Shape Layer 6", + "parent": 13, + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100 }, + "r": { "a": 0, "k": -105.178 }, + "p": { "a": 0, "k": [145.646, -87.164, 0], "l": 2 }, + "a": { "a": 0, "k": [0, 0, 0], "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "l": 2 } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ks": { + "a": 0, + "k": { + "i": [ + [1.5, 0], + [6.612, 7.238], + [-2.376, 0] + ], + "o": [ + [-1.226, 0], + [-4.067, 24.261], + [13, 0] + ], + "v": [ + [-109.5, -144], + [-145.991, -163.184], + [-120.836, -120.957] + ], + "c": false + } + }, + "nm": "Path 1" + }, + { + "ty": "fl", + "c": { "a": 0, "k": [0.037, 0.139, 0.273, 1] }, + "o": { "a": 0, "k": 100 }, + "r": 1, + "nm": "Fill 1" + }, + { + "ty": "tr", + "p": { "a": 0, "k": [0, 0] }, + "a": { "a": 0, "k": [0, 0] }, + "s": { "a": 0, "k": [100, 100] }, + "r": { "a": 0, "k": 0 }, + "o": { "a": 0, "k": 100 }, + "sk": { "a": 0, "k": 0 }, + "sa": { "a": 0, "k": 0 }, + "nm": "Transform" + } + ], + "nm": "Shape 1" + } + ], + "ip": 0, + "op": 144, + "st": 0, + "ct": 1 + }, + { + "ind": 13, + "ty": 2, + "nm": "Beak 2", + "parent": 10, + "refId": "image_3", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100 }, + "r": { + "a": 1, + "k": [ + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 0, + "s": [118.678] + }, + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 4, + "s": [96.678] + }, + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 8, + "s": [118.678] + }, + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 12, + "s": [96.678] + }, + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 16, + "s": [118.678] + }, + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 20, + "s": [96.678] + }, + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 24, + "s": [118.678] + }, + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 28, + "s": [96.678] + }, + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 32, + "s": [118.678] + }, + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 36, + "s": [96.678] + }, + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 40, + "s": [118.678] + }, + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 47, + "s": [118.678] + }, + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 52, + "s": [96.678] + }, + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 89, + "s": [96.678] + }, + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 127, + "s": [118.678] + }, + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 131, + "s": [96.678] + }, + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 135, + "s": [118.678] + }, + { + "i": { "x": [0.833], "y": [0.833] }, + "o": { "x": [0.167], "y": [0.167] }, + "t": 139, + "s": [96.678] + }, + { "t": 144, "s": [118.678] } + ] + }, + "p": { "a": 0, "k": [65.182, 150.499, 0], "l": 2 }, + "a": { "a": 0, "k": [61.573, 36.324, 0], "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "l": 2 } + }, + "ao": 0, + "ef": [ + { + "ty": 21, + "nm": "Fill", + "np": 9, + "en": 1, + "ef": [ + { "ty": 10, "nm": "Fill Mask", "v": { "a": 0, "k": 0 } }, + { "ty": 7, "nm": "All Masks", "v": { "a": 0, "k": 0 } }, + { "ty": 2, "nm": "Color", "v": { "a": 0, "k": [0.035, 0.141, 0.275, 1] } }, + { "ty": 7, "nm": "Invert", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Horizontal Feather", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Vertical Feather", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Opacity", "v": { "a": 0, "k": 1 } } + ] + } + ], + "ip": 0, + "op": 144, + "st": 0 + }, + { + "ind": 14, + "ty": 2, + "nm": "Comb", + "parent": 10, + "refId": "image_4", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100 }, + "r": { "a": 0, "k": 0 }, + "p": { "a": 0, "k": [237.2, 12.084, 0], "l": 2 }, + "a": { "a": 0, "k": [50.248, 81.606, 0], "l": 2 }, + "s": { + "a": 1, + "k": [ + { + "i": { "x": [0.667, 0.667, 0.667], "y": [1, 1.25, 1] }, + "o": { "x": [0.333, 0.333, 0.333], "y": [0, 0, 0] }, + "t": 50, + "s": [100, 100, 100] + }, + { + "i": { "x": [0.667, 0.667, 0.667], "y": [1, 1, 1] }, + "o": { "x": [0.333, 0.333, 0.333], "y": [0, 0.125, 0] }, + "t": 53, + "s": [100, 78, 100] + }, + { + "i": { "x": [0.667, 0.667, 0.667], "y": [1, 1, 1] }, + "o": { "x": [0.333, 0.333, 0.333], "y": [0, 0, 0] }, + "t": 56, + "s": [100, 122, 100] + }, + { "t": 61, "s": [100, 100, 100] } + ], + "l": 2 + } + }, + "ao": 0, + "ef": [ + { + "ty": 21, + "nm": "Fill", + "np": 9, + "en": 1, + "ef": [ + { "ty": 10, "nm": "Fill Mask", "v": { "a": 0, "k": 0 } }, + { "ty": 7, "nm": "All Masks", "v": { "a": 0, "k": 0 } }, + { "ty": 2, "nm": "Color", "v": { "a": 0, "k": [0.016, 0.251, 0.165, 1] } }, + { "ty": 7, "nm": "Invert", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Horizontal Feather", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Vertical Feather", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Opacity", "v": { "a": 0, "k": 1 } } + ] + } + ], + "ip": 0, + "op": 144, + "st": 0 + }, + { + "ind": 15, + "ty": 2, + "nm": "Left Leg", + "refId": "image_5", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100 }, + "r": { "a": 0, "k": 0 }, + "p": { "a": 0, "k": [382.643, 537.776, 0], "l": 2 }, + "a": { "a": 0, "k": [51.011, 38.263, 0], "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "l": 2 } + }, + "ao": 0, + "ef": [ + { + "ty": 21, + "nm": "Fill", + "np": 9, + "en": 1, + "ef": [ + { "ty": 10, "nm": "Fill Mask", "v": { "a": 0, "k": 0 } }, + { "ty": 7, "nm": "All Masks", "v": { "a": 0, "k": 0 } }, + { "ty": 2, "nm": "Color", "v": { "a": 0, "k": [0.016, 0.251, 0.165, 1] } }, + { "ty": 7, "nm": "Invert", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Horizontal Feather", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Vertical Feather", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Opacity", "v": { "a": 0, "k": 1 } } + ] + } + ], + "ip": 0, + "op": 144, + "st": 0 + }, + { + "ind": 16, + "ty": 2, + "nm": "Right Leg", + "refId": "image_6", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100 }, + "r": { "a": 0, "k": 0 }, + "p": { "a": 0, "k": [547.327, 540.764, 0], "l": 2 }, + "a": { "a": 0, "k": [31.921, 44.111, 0], "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "l": 2 } + }, + "ao": 0, + "ef": [ + { + "ty": 21, + "nm": "Fill", + "np": 9, + "en": 1, + "ef": [ + { "ty": 10, "nm": "Fill Mask", "v": { "a": 0, "k": 0 } }, + { "ty": 7, "nm": "All Masks", "v": { "a": 0, "k": 0 } }, + { "ty": 2, "nm": "Color", "v": { "a": 0, "k": [0.016, 0.251, 0.165, 1] } }, + { "ty": 7, "nm": "Invert", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Horizontal Feather", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Vertical Feather", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Opacity", "v": { "a": 0, "k": 1 } } + ] + } + ], + "ip": 0, + "op": 144, + "st": 0 + }, + { + "ind": 17, + "ty": 2, + "nm": "Right Wing", + "parent": 10, + "refId": "image_7", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100 }, + "r": { + "a": 1, + "k": [ + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 0, + "s": [0] + }, + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.333], "y": [0] }, + "t": 53, + "s": [0] + }, + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 61, + "s": [206] + }, + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 64, + "s": [195] + }, + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 67, + "s": [206] + }, + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 70, + "s": [195] + }, + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 73, + "s": [206] + }, + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 76, + "s": [195] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 88, + "s": [195] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 100.745, + "s": [51] + }, + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.167], "y": [0] }, + "t": 118.334, + "s": [51] + }, + { "t": 135, "s": [0] } + ] + }, + "p": { "a": 0, "k": [249.876, 181.978, 0], "l": 2 }, + "a": { "a": 0, "k": [-44.314, 3.47, 0], "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "l": 2 } + }, + "ao": 0, + "ef": [ + { + "ty": 21, + "nm": "Fill", + "np": 9, + "en": 1, + "ef": [ + { "ty": 10, "nm": "Fill Mask", "v": { "a": 0, "k": 0 } }, + { "ty": 7, "nm": "All Masks", "v": { "a": 0, "k": 0 } }, + { "ty": 2, "nm": "Color", "v": { "a": 0, "k": [0.078, 0.208, 0.376, 1] } }, + { "ty": 7, "nm": "Invert", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Horizontal Feather", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Vertical Feather", "v": { "a": 0, "k": 0 } }, + { "ty": 0, "nm": "Opacity", "v": { "a": 0, "k": 1 } } + ] + } + ], + "ip": 0, + "op": 144, + "st": 0 + } + ] + } + ], + "layers": [ + { + "ind": 1, + "ty": 0, + "nm": "Bird Comp_Export_Dark", + "refId": "comp_0", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100 }, + "r": { "a": 0, "k": 0 }, + "p": { "a": 0, "k": [136.234, 134, 0], "l": 2 }, + "a": { "a": 0, "k": [450, 489, 0], "l": 2 }, + "s": { "a": 0, "k": [29, 29, 100], "l": 2 } + }, + "ao": 0, + "w": 900, + "h": 978, + "ip": 0, + "op": 144, + "st": 0 + } + ], + "markers": [] +} diff --git a/apps/client/public/assets/json/character_dark.json b/apps/client/public/assets/json/character_dark.json new file mode 100644 index 0000000..62cdec9 --- /dev/null +++ b/apps/client/public/assets/json/character_dark.json @@ -0,0 +1 @@ +{"v":"5.12.1","fr":23.976,"ip":0,"op":97,"w":513,"h":478,"nm":"Coming Soon_Ladder Dark","assets":[{"id":"image_0","w":67,"h":29,"u":"","p":"data:image/webp;base64,UklGRlYCAABXRUJQVlA4WAoAAAAQAAAAQgAAHAAAQUxQSLIAAAABcEhbbyYFoQiDMAgfQhAWYRA+hEUIQhGCsAiDMAb7v5t+HYCImAAbjAsjfw3SsZiy93t1xrZq4HYfewTG8S6YGBR3zesQv6vGgHbI3K91vAuvZbtSVPlduhWFlhftWqxZ79pRs4llze0ElvsJ8ATaoRZmIAn8wrs6ze9fM0msC+8T8Nu8bn0+nIEZputmtkXOdbHPDRsz50j7t8HJzF2pt79+BZxkz8xjxB4w4YbCxX4EVlA4IH4BAADwCACdASpDAB0APm0ukUWkIqGWbf6oQAbEswbAAPEPAdBhOoYOEBtm+foeIAxQRhy3CS9xenibbt0wIy4AOFK/822kMPNeFZAJhM6MBz3vgAD+/qU2yf301HZ1G2jCwclp8FLQixtki4p0vXseVrNyyzs8S+PjGwTzFZToKeVqaEPFmZtuBi3CViEFnuFjWpL/6aHXBRCB7vz0TznBc/JW2xLkC5UcRE8VZ0kILmGetm7GB13iZeAU+iNi2adAkDMPcLzQevM3ZAD82ZU6BFKvBs+Y3FfS/7iJTwQ4P/hEdHSZm+Yn4hQJbr7XhD47KGcYisl0sC9Un6KIQlatDGh8kaOvMir/W87/RPd8ig2QCSzx3vkaIGF3VddYftPsamWfQf7bLgRBRZ7WbGTwW1qHSntIsTdcT4Cf5o+wUMk5k5/ZKcbUND6Ovtt18RzNbLSSiuEu/S2B57wyWGhhohh9X4aiyrKQK7nAFQgFq0jpcbRigKE9V08I6c2hYAAA","e":1},{"id":"image_1","w":11,"h":16,"u":"","p":"data:image/webp;base64,UklGRrQAAABXRUJQVlA4WAoAAAAQAAAACgAADwAAQUxQSFMAAAABYEhtW50X4UcYwhBCGMIQQgghhBBCCGEIQ2gEt/8yhYiYANY2qqBl3vd9GOXWSY1/orqa911hV3pBppOhOB3ksgaQI5yRZFRFV8mQed8NW/IGAABWUDggOgAAALABAJ0BKgsAEAABQCYlsAJ0OIABiAAA/vlnH/YiBw0F2EL0vlbPB7PMGefoNX5gK4TNWQteEnoAAAA=","e":1},{"id":"image_2","w":54,"h":73,"u":"","p":"data:image/webp;base64,UklGRmoDAABXRUJQVlA4WAoAAAAQAAAANQAASAAAQUxQSD8BAAABkFbbdt5GF8KDIAiCIAiB8CAYgiAIgiAIgiAIghjUQfD6NTP3ymv+R8QE4OTS52U4vkdEvPNBdUfMEb/ukk9Z8a/Ljmjx7+uEFMxyQKPUA/YzUlBd55yi6xzTbcqGPAV16JxTdY1TdItjMgvqgrxwmq5yXDc5pgvqgrxwmq5xsm5RbshTULvu4rx0i3JDnoLadY2TdTdlQ+5BvXSbYzIPaofaNifLalAn1Dm4RWWLM6HuwS2qK7gTYg9yEXmQB7Qe7KSpwa5Q2gj2NkXZQS/gWw9+A93qO/jbWKm9Q5lBTdcMbcW/p6uvUA8QR+i3MV4fsncGdcoKuEvlIIfY8QjHIxyPcDzC8YQ7Q5loK0FaWN3wgPsFNWcmPOB2HEhohgeMhDP970bBqfUv7p5wrI0/TDcc7PFzXAlnpzlqwf8SAFZQOCAEAgAAUA0AnQEqNgBJAD5lKo9FpCKhGZ3+AEAGRKANGo1KQDbAbhveFqBL+SvPAK1KwTt7GOzXAm5M/7UDkN2F9yhv5do0P/d1oMusG1KR8cbLdQGVpiforXAOgvr59f57U5haJUkT40Q39ShbE/6PREhmxYB2kAD+/gbVj/7zQy+k0Z3FTB0MHnkhVGhrFUnkj4/dFeeLrl6x5C2z8/tHyWEt91spYJzVR9IlUQLO/MXHNX1Hi88QDYXLdYKrOyLEqsCCAzsLYvvB9aI3Yam99n/0gcS8bVaHLPpkHa1dbGnnG1R7X/uDnk9JkQqPRRj8rr0hzh7QtAsSzh5p0z3TYuva9l+2dFZzlFpXJyUxV/pF1fVCHWCse+3Ap4e9OMyjv/c0DN0q/gBd6rgw7/8lGoxF0RdLKaRcr97lGo4MpwA8rueGyhrHw2onXogSUfK0OKrwE0ZR/kmFyaHiMBUsYpjsBsXqAZuqEs0CL6RuGEf/QgODn45h/Xa3uYIR3oPTCEOOKVPDxKpWHEX7mtqu1miH2f7gTj7vqYGW5mQ82mHg5S7eo3czWAmtUDPc3NuenspHQ6W+awVIZ7BbhXxn5FUs/WIWVs3HrMJcjnBNFRHOeeKZ8gAUY2/1OtfOiT7VHLb/sqMjUgHp/+4AiccDsdDVyNcUz31c1wVt+kDBdSS20HEAAAAA","e":1},{"id":"image_3","w":90,"h":76,"u":"","p":"data:image/webp;base64,UklGRhYEAABXRUJQVlA4WAoAAAAQAAAAWQAASwAAQUxQSHABAAABcE5bW2Y9CCGEEEIIgxBCCCGEEMIghBBC6xIUwfvjzvQxPQARMQE42D4rEDU2xFxksKaLgHEhF1lar5OsT0W2ZnWEcanIB5v5mg13k6928yHjs3y7m29ofzf5flH7rljl0LTJpiYH2w06Vjm7LtNJzg9rVBKGXa24unAMC6KwbHNJeLqZJETLhBeqZkh3LmkoCdeuBrSwdQOJThnodES/XMLXv0RC9SUTEvMkjCOx8mAoif6znDyxTEyYWQCKVAAAUvmvcZK/TEoDiKQsAEcqADDE0Djdfzen/OeJaWKoxCKxi1J6QGcUnm5G7skxMk+aUMNr4ZPeIp/rzdLpGKQTRjIbPRLIBIxeXH5qyHCxGKcSMVmIZMx6HkVNWRpFYZ5FUViYOSSFlY5Bd1ir+nlZY7U7rTpsvI+qDltVOSc77FbljOI1Pqjuz7Xba3z1qh/K0Rl829V9OQdvNY40PrcVJecYvLU4Xlnrw6Oz1hqcCVZQOCCAAgAAUBAAnQEqWgBMAD5pLpNFpCKhmIsFbEAGhLGAaPYKju6YBtq+eq0yufHfoAuJY0U0G6yzPlTrhGxQ9mOGLu6Zx/O7f9zKpDltGBgLNeodb+LLGf+Jb5smKbYTMc+SgXJZdfALTr7nMc+ma3G9YZJeaCfvlMjNn/k5qXVnTNhkhCLGNXurIf/lP58DAAD+WCF9swb0nFX6XDxsurDjFDnjHrlNYZzq13mv5tcR7Fbd4YqJY5wgEJDMc7rKv6sDIeswLTGdrj0XS035skh7rOr4QTtjfmeBxV2s6Vl0W4GDfQae36qPOZtxvXuebnzTFt/0tHu6Gzk8fI6uzfiVd4EQYxsrlR4ukDLDSq226uHKuEy+mzNn92moPdh/sg+10k/fZ7//90S//unf//7oqxTwi/3q7GAWleTebD/0NVwhM0JfbWwpS/TFE3QxdPw5vhmczyjcJYBjxS79UGywwA+mk90zP9zAr38cOEYET5xW/gnD8Y6TRj6/zoF2ofqOJvH6cJG/wDMVvQvRZsnICmVVql72EKrDhN/U5XHGe4wwAznQ846UAu1WniumCt8ww0TDR2OpEoh+fRPQZdv5cS61ziOjaCUMCJoUmWKjyNs402LToY3i+RzsKTtZ3Lc4IFrurVaS6sAtcNDevdbuXNs+pLt6hMSEZlTKqfU0EXaMuK1bzP7+I8gMbx1w7zs67gxoSSu/fMTGtyyi/5Ba5uXmby4RwpL8speD4vUygMoQJc+RQ0f2w5bXeukAsHbMS1JSi3BodUlAi6fLbGo/Z5oXbxbOOebarrbB0Mr8ZA0ZButp9353Pkr/LwRbA3V9kdNun/4h0dHnWdBSiPf+t3gAAA==","e":1},{"id":"image_4","w":19,"h":65,"u":"","p":"data:image/webp;base64,UklGRvwBAABXRUJQVlA4WAoAAAAQAAAAEgAAQAAAQUxQSJoAAAABcBVJkhWVhJWAhJUwEk7CSkDCSEACEpAwEpCABBy873riXt8RMQG83hn6vNlL1o/ztm0O1Ki1jfP2dAR8EwPolQ0wqUCRDJAeQCieMQCuRFZTNsDeoWQYlAzewb9d/A01w75KLw3gkr/PlBGSvc8qFdhk3iPA3mHM8CSXWoa/yZSxFkLaWsaSsdUMN23p6NcX1hhax9XuK08BVlA4IDwBAAAQCACdASoTAEEAPm0ylEckIyIhKbVaSIANiWIAwxlsvA7Y/oAwnL0AdCB6nYBCmuDL0kKBqotYXRIRcO6ABZtirH5deazqwioAAP74+qpIPdnH7VO/GAMfxPo6Rj0xfSlb+b70TTbP8Jw/ZeZ9TfSTJCj2zF7E//gEIcjRp+SBxqsq95QQmyR6P8ifbmMMWYUcptz3RpWTmIaiAYVzcOt8Zyvdihttd3WsW/Zq2RxShRLyPNEvOBWeZzCk10uWhnIqkgBH1WTTtgKSg27Ad+pbnXuXHDYS+zTBr8xvmtnId5vObN8J4ylGLY23TPg3eoU6u1tiq/xcnBDLtFVt2FywPrHfENbfxkQGy0Azy0F1kNG0hXNye0wh8WCTIazv47/UV2e3ZqlF2rODCcLjDBYjUt4G0X//0IYAAAAA","e":1},{"id":"image_5","w":28,"h":63,"u":"","p":"data:image/webp;base64,UklGRuYCAABXRUJQVlA4WAoAAAAQAAAAGwAAPgAAQUxQSOYAAAABgE3bdlhrIwQhCEE4CEUoQhAOQhEOwkUIQhGCkBKcr+7dvCcQEROAT4sVfN4iL8oqgGKHx5iZmYOxnGMkz7TUG4GlncxPc6Zrg2naYrCkrMzQjHHNGdN+TNFuBlNKamjGuHYyh+ZM0wYDbVG3lIUZmjGuOdO1YEwbWxZTtWTwb9oW23JuCW0wUwuipn4QXXtATi0IS70SoQXea+qVCC3wXlN+ChFax3tN+QYZmhEt5QA5pKcSlrKDnFohPOUAubRGHClPkK7Fls40zRjMLccWXErnEIILOB/KFJRrvYyKL83dvVf8XVZQOCDaAQAAkAwAnQEqHAA/AD5tMJNHpCKhoSgYDACADYlsAMgXRztfoHmCUT+q7OwoDQAbhTeFPQAqwD+AVmnefhrGdN2Su7IGDMaD7owzSCWE5CdSSFmP6O0kO5OIeLR0AHGNWPKyPhZbuiOITbbuE323gAD+22YsAmdqwX+txaeVp+FhVZGyrtSV//5Ldv/ycieBTezr/8Oa4nl0FCJ4HVCOEQf1/NkOXCff/9tlv77LHMeBgrSSj1qJX86nQWBQLnK1Vrxj1tbvyuU+zCjj/LE6/Cr11j3jmS5xdefNhyB6QToov9r5hO+sG5/dzFi1wbJivP2iB5DcjWxmBk3xpRel7QQFpue3W91Gyq6KfAq7Ww5HagfmENG84hX9hpS5Pl2xfhdWjChaSUkYv7gUw1Zzqw/TNxFZklRCpOCe7kstIkuxVWk9BLZ0S7/E3ywslcIJ2fYTiTvxkmFhwIjah6bAzWT7en0peDlDICEy7ZzFYZKQJTQQPIv/xonTChLs0+cLmg/7VeHcTX9HsW27TGQpFZq3BsC8dkfe5kVAegzTAoJyVYe+y1OEXQnmsIsbJ8tJfO+Dyb27x6+OQHHFobyi/J2vLGhY3T/yIJ4Jml2x9+eT0ZXg/0eBxL4gAAAA","e":1},{"id":"image_6","w":202,"h":202,"u":"","p":"data:image/webp;base64,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","e":1},{"id":"image_7","w":50,"h":153,"u":"","p":"data:image/webp;base64,UklGRuYCAABXRUJQVlA4WAoAAAAQAAAAMQAAmAAAQUxQSPAAAAABgFBbe9vmg/BDEARB+CEYgiEIgiAYQiAIgiAIgiD8DL5Oj697noiYgJoh37mZHmPRI3vSI+sL4HQ9spkeo+iRI+uRm+kxFj2yJz2yvgBO1yOb6TGKHjmyHrmZHmPRI3vSI6vpcboe2ZIeo+iRw/XIzfQYqx7Zkx5ZTY/T9Uj/10fWm9DLcrFAat7qalCKFc/qZMhV6CW9gF7/zLst7mUqjYQni84wPLvKZOxsIg17s0jdBRHf138ItH2mse6a0MDc4yo5ntuggtyfiAU6QC61OI5fc/ZvOHVXE/FdqwjajgFVG89EkgHqEzeDdHY3HAVWUDgg0AEAAFAMAJ0BKjIAmQA+bTCVRiQjIiEudVnQgA2JQMUAIWw1P6Br1fXt6PlNvAbZvzAeRL+s3uU/xe+Abx6RF4U5wvrTKsj/+KQ0oiD0yiH4RSJ3OkfSS8PtfrgJ6K3vGaUTvjQ7tIl+8WK9j5wAAP7uJx+CyezhS70zJ+SKGlXxN9kTMxsY5jz4pdl+f//trUTw1slETo0QFnRSZFb+gkfv9PgyqgiTevH1jEESSdBNmt+la51ZfHSUBT/IWYf7zm30qpk2AvlSIUa9HfLgNLGwAZps/ZqyiFpTCbd+w9fNd3csBSr+yiaa+Acs0/jkB9F+iAoVUxkwriU8Dp1VOe4YqCIHI7+rc+Rajtyio6pAiooTqDOePc0QAUCceTScbjghKOTiYn7iaNvSyaM8lwLItSf+z9xrT5VyjAgNa+GKf5bzZ/3Es7HNocY5tFIdjKsODrvX/10uN2m5C4QNy3PnN7S2+5pdx/1LoXut8Io4fciVlFf/+2sLSJC0J1OMfeRNjoVdJvhU6MIiYe2mFIAatfxhfPGDzfyPDntP/1Z/Ge91qsnWiBJddEHzvi5dKko3+4HXAL+CCGNglYa1sKOciomMd4kj+SHqcUe8D/P0AAAA","e":1},{"id":"image_8","w":27,"h":55,"u":"","p":"data:image/webp;base64,UklGRqICAABXRUJQVlA4WAoAAAAQAAAAGgAANgAAQUxQSN4AAAABgFTbVlzpSUDCk4CEJwEJSEACEpCABCQgIRIiIfmjmt1qaC6lICImQLiWhK0dMFIGcDuKXgBQhBle/O2MiDGjYr5XwctY9RsRy7bmsR6W3LuRlzp4Cbt9wb0HKrafmYE46wwdGZg2apQwUFC/7E/hIP25KW8SEQlg3l7+FsajMrwZJkMFsco4MnRSCE2mnRBnD8HPQJSpP2H/TE/EE/UE9EQ+8dGBoyAPhPO6wUVBHDROGSROH/gT8lDKqFJsZIwm02uvuVlYCzF5WW0LT5Rddw0uMyf7rgJoKmSnQgRWUDggngEAABAKAJ0BKhsANwA+aSaPRaQiIRn8zqhABoS0AGOigBdgG8oYA1/HfoA7CCUA7AawMYtz4lsIwy5c9RqgGyYJz1X8DQs3qJ9g0SXXWKtfAJYFy/x+43PW7igAAP2zSYFMpowUXTRAcurSbUbs8/X9nfL9naJFeagOL8g//DXhgo1vapMaiMe9Ah0iv4Y2a8gt0+f3h+mPCFXvLBN+Pl5Y7ZV8UZt/UwQMfjeV3c4JeaKG/FPLK3yH/IfOIQ6j0mcc+rIAtQovIpo1sG+XVuD/mfo+/14xzwm9YFNZWcj0NP9ErishZ1mTZ/4iTitOvE090wtVOYWW3/vEKa0aZ3pbkcKYSaN8aNNr9b2G2Ru8wzDG9etHvl+TX+E8tWVEMBJ0n7L6AYrEsTrYzg9yubvMMWlUsbrKnEjr9EY/CNU6CnOhFE4mq3+MMhI/CxRF+amqOSLWfa6SrsNRcmfvkfVIRAjhwyjGu/Gb3KGNS+7+mwv77t1fwJL45uUZuLYqF+zms6UoO6ISTLMXvyQpkKt6g+FfGn///uKFWeK+qkAAAA==","e":1},{"id":"image_9","w":76,"h":194,"u":"","p":"data:image/webp;base64,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","e":1},{"id":"comp_0","nm":"Character + BG Dark","fr":23.976,"layers":[{"ind":1,"ty":0,"nm":"Character Dark","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[350,239,0],"l":2},"a":{"a":0,"k":[300,239,0],"l":2},"s":{"a":0,"k":[100,100,100],"l":2}},"ao":0,"w":600,"h":478,"ip":0,"op":144,"st":0},{"ind":2,"ty":0,"nm":"Background Dark","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[320,151,0],"l":2},"a":{"a":0,"k":[256.5,150,0],"l":2},"s":{"a":0,"k":[100,100,100],"l":2}},"ao":0,"w":513,"h":300,"ip":0,"op":144,"st":0}]},{"id":"comp_1","nm":"Character Dark","fr":23.976,"layers":[{"ind":1,"ty":3,"nm":"Main Null","sr":1,"ks":{"o":{"a":0,"k":0},"r":{"a":0,"k":0},"p":{"a":0,"k":[300,239,0],"l":2},"a":{"a":0,"k":[0,0,0],"l":2},"s":{"a":0,"k":[100,100,100],"l":2}},"ao":0,"ip":0,"op":144,"st":0},{"ind":2,"ty":2,"nm":"Hat","parent":8,"refId":"image_0","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":67,"s":[20]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":82,"s":[-10]},{"t":90,"s":[0]}]},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[45.581,-4.439,0],"to":[2.5,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":67,"s":[60.581,-4.439,0],"to":[0,0,0],"ti":[15.023,0.655,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":75,"s":[45.697,-46.874,0],"to":[-1.949,-0.085,0],"ti":[0.703,0,0]},{"t":82,"s":[45.581,-4.439,0]}],"l":2},"a":{"a":0,"k":[33.133,14.23,0],"l":2},"s":{"a":0,"k":[100,100,100],"l":2}},"ao":0,"ef":[{"ty":21,"nm":"Fill","np":9,"en":1,"ef":[{"ty":10,"nm":"Fill Mask","v":{"a":0,"k":0}},{"ty":7,"nm":"All Masks","v":{"a":0,"k":0}},{"ty":2,"nm":"Color","v":{"a":0,"k":[0.024,0.435,0.286,1]}},{"ty":7,"nm":"Invert","v":{"a":0,"k":0}},{"ty":0,"nm":"Horizontal Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Vertical Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Opacity","v":{"a":0,"k":1}}]}],"ip":0,"op":144,"st":0},{"ind":3,"ty":2,"nm":"Eyes","parent":8,"refId":"image_1","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":-18},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":41,"s":[69.257,22.635,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":59,"s":[69.257,22.635,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":62,"s":[66.027,27.232,0],"to":[0,0,0],"ti":[0,0,0]},{"t":66,"s":[69.257,22.635,0]}],"l":2},"a":{"a":0,"k":[5.089,7.974,0],"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":0,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":64,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":66,"s":[100,10,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":78,"s":[100,10,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":80,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":101,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":103,"s":[100,10,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":105,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":108,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":110,"s":[100,10,100]},{"t":112,"s":[100,100,100]}],"l":2}},"ao":0,"ef":[{"ty":35,"nm":"Transform","np":14,"en":1,"ef":[{"ty":3,"nm":"Anchor Point","v":{"a":0,"k":[5.5,8]}},{"ty":3,"nm":"Position","v":{"a":0,"k":[5.5,8]}},{"ty":7,"nm":"Uniform Scale","v":{"a":0,"k":1}},{"ty":0,"nm":"Scale Height","v":{"a":0,"k":100}},{"ty":0,"nm":"Scale Width","v":{"a":0,"k":100}},{"ty":0,"nm":"Skew","v":{"a":0,"k":0}},{"ty":0,"nm":"Skew Axis","v":{"a":0,"k":0}},{"ty":0,"nm":"Rotation","v":{"a":0,"k":21}},{"ty":0,"nm":"Opacity","v":{"a":0,"k":100}},{"ty":7,"nm":"Use Composition’s Shutter Angle","v":{"a":0,"k":1}},{"ty":0,"nm":"Shutter Angle","v":{"a":0,"k":0}},{"ty":7,"nm":"Sampling","v":{"a":0,"k":1}}]},{"ty":21,"nm":"Fill","np":9,"en":1,"ef":[{"ty":10,"nm":"Fill Mask","v":{"a":0,"k":0}},{"ty":7,"nm":"All Masks","v":{"a":0,"k":0}},{"ty":2,"nm":"Color","v":{"a":0,"k":[0.039,0.106,0.188,1]}},{"ty":7,"nm":"Invert","v":{"a":0,"k":0}},{"ty":0,"nm":"Horizontal Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Vertical Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Opacity","v":{"a":0,"k":1}}]}],"ip":0,"op":144,"st":0},{"ind":4,"ty":2,"nm":"Right Hand","parent":8,"refId":"image_2","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[79.223,47.54,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":12,"s":[70.723,47.54,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":24,"s":[79.223,47.54,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":36,"s":[70.723,47.54,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":48,"s":[79.223,47.54,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":60,"s":[70.723,47.54,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":72,"s":[79.223,47.54,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":84,"s":[70.723,47.54,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":96,"s":[79.223,47.54,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":108,"s":[70.723,47.54,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":120,"s":[79.223,47.54,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":132,"s":[70.723,47.54,0],"to":[0,0,0],"ti":[0,0,0]},{"t":144,"s":[79.223,47.54,0]}],"l":2},"a":{"a":0,"k":[5.405,59.062,0],"l":2},"s":{"a":0,"k":[100,100,100],"l":2}},"ao":0,"ef":[{"ty":21,"nm":"Fill","np":9,"en":1,"ef":[{"ty":10,"nm":"Fill Mask","v":{"a":0,"k":0}},{"ty":7,"nm":"All Masks","v":{"a":0,"k":0}},{"ty":2,"nm":"Color","v":{"a":0,"k":[0.11,0.286,0.518,1]}},{"ty":7,"nm":"Invert","v":{"a":0,"k":0}},{"ty":0,"nm":"Horizontal Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Vertical Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Opacity","v":{"a":0,"k":1}}]}],"ip":0,"op":144,"st":0},{"ind":5,"ty":4,"nm":"Shape Layer 2","parent":4,"tt":1,"tp":8,"sr":1,"ks":{"o":{"a":0,"k":52},"r":{"a":0,"k":-11},"p":{"a":0,"k":[145.359,29.094,0],"l":2},"a":{"a":0,"k":[0,0,0],"l":2},"s":{"a":0,"k":[100,100,100],"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0]],"o":[[0,0]],"v":[[-253.857,47.861]],"c":false}},"nm":"Path 1"},{"ty":"fl","c":{"a":0,"k":[0.039,0.106,0.188,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 2"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-118.057,-13.905],[-143.573,-8.462],[-149.25,14.5],[-140.5,23.25],[-114,17.5]],"c":true}},"nm":"Path 1"},{"ty":"fl","c":{"a":0,"k":[0.039,0.106,0.188,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1"}],"ip":0,"op":144,"st":0,"ct":1},{"ind":6,"ty":3,"nm":"Null 1","parent":9,"sr":1,"ks":{"o":{"a":0,"k":0},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":20,"s":[18]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":64,"s":[18]},{"t":69,"s":[0]}]},"p":{"a":0,"k":[8.955,5.655,0],"l":2},"a":{"a":0,"k":[0,0,0],"l":2},"s":{"a":0,"k":[14.5,14.5,100],"l":2}},"ao":0,"ip":0,"op":144,"st":0},{"ind":7,"ty":2,"nm":"Head 2","parent":6,"refId":"image_3","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":189,"s":[11]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":201,"s":[15]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":258,"s":[15]},{"t":273,"s":[11]}]},"p":{"a":0,"k":[-97.877,-247.176,0],"l":2},"a":{"a":0,"k":[44.657,37.904,0],"l":2},"s":{"a":0,"k":[689.655,689.655,100],"l":2}},"ao":0,"ef":[{"ty":21,"nm":"Fill","np":9,"en":1,"ef":[{"ty":10,"nm":"Fill Mask","v":{"a":0,"k":0}},{"ty":7,"nm":"All Masks","v":{"a":0,"k":0}},{"ty":2,"nm":"Color","v":{"a":0,"k":[0.11,0.286,0.518,1]}},{"ty":7,"nm":"Invert","v":{"a":0,"k":0}},{"ty":0,"nm":"Horizontal Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Vertical Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Opacity","v":{"a":0,"k":1}}]}],"ip":0,"op":144,"st":0},{"ind":8,"ty":2,"nm":"Head","parent":6,"td":1,"refId":"image_3","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":189,"s":[11]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":201,"s":[15]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":258,"s":[15]},{"t":273,"s":[11]}]},"p":{"a":0,"k":[-97.877,-247.176,0],"l":2},"a":{"a":0,"k":[44.657,37.904,0],"l":2},"s":{"a":0,"k":[689.655,689.655,100],"l":2}},"ao":0,"ef":[{"ty":21,"nm":"Fill","np":9,"en":1,"ef":[{"ty":10,"nm":"Fill Mask","v":{"a":0,"k":0}},{"ty":7,"nm":"All Masks","v":{"a":0,"k":0}},{"ty":2,"nm":"Color","v":{"a":0,"k":[0.11,0.286,0.518,1]}},{"ty":7,"nm":"Invert","v":{"a":0,"k":0}},{"ty":0,"nm":"Horizontal Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Vertical Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Opacity","v":{"a":0,"k":1}}]}],"ip":0,"op":144,"st":0},{"ind":9,"ty":2,"nm":"Right Leg","parent":19,"refId":"image_4","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[59.53,2.877,0],"l":2},"a":{"a":0,"k":[9.306,32.243,0],"l":2},"s":{"a":0,"k":[100,100,100],"l":2}},"ao":0,"ef":[{"ty":21,"nm":"Fill","np":9,"en":1,"ef":[{"ty":10,"nm":"Fill Mask","v":{"a":0,"k":0}},{"ty":7,"nm":"All Masks","v":{"a":0,"k":0}},{"ty":2,"nm":"Color","v":{"a":0,"k":[0.078,0.208,0.376,1]}},{"ty":7,"nm":"Invert","v":{"a":0,"k":0}},{"ty":0,"nm":"Horizontal Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Vertical Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Opacity","v":{"a":0,"k":1}}]}],"ip":0,"op":144,"st":0},{"ind":10,"ty":2,"nm":"Left Leg","parent":8,"refId":"image_5","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[-11]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":19,"s":[6]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":65,"s":[6]},{"t":72,"s":[-11]}]},"p":{"a":0,"k":[41.124,75.39,0],"l":2},"a":{"a":0,"k":[14.497,3.557,0],"l":2},"s":{"a":0,"k":[100,100,100],"l":2}},"ao":0,"ef":[{"ty":21,"nm":"Fill","np":9,"en":1,"ef":[{"ty":10,"nm":"Fill Mask","v":{"a":0,"k":0}},{"ty":7,"nm":"All Masks","v":{"a":0,"k":0}},{"ty":2,"nm":"Color","v":{"a":0,"k":[0.078,0.208,0.376,1]}},{"ty":7,"nm":"Invert","v":{"a":0,"k":0}},{"ty":0,"nm":"Horizontal Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Vertical Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Opacity","v":{"a":0,"k":1}}]}],"ip":0,"op":144,"st":0},{"ind":11,"ty":2,"nm":"Brush","parent":4,"refId":"image_6","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":7},"p":{"a":0,"k":[-73.296,106.626,0],"l":2},"a":{"a":0,"k":[18.265,190.145,0],"l":2},"s":{"a":0,"k":[100,100,100],"l":2}},"ao":0,"ef":[{"ty":21,"nm":"Fill","np":9,"en":1,"ef":[{"ty":10,"nm":"Fill Mask","v":{"a":0,"k":0}},{"ty":7,"nm":"All Masks","v":{"a":0,"k":0}},{"ty":2,"nm":"Color","v":{"a":0,"k":[0.141,0.365,0.659,1]}},{"ty":7,"nm":"Invert","v":{"a":0,"k":0}},{"ty":0,"nm":"Horizontal Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Vertical Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Opacity","v":{"a":0,"k":1}}]}],"ip":0,"op":144,"st":0},{"ind":13,"ty":2,"nm":"Paint","refId":"image_7","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[233.001,200.001,0],"l":2},"a":{"a":0,"k":[24.751,76.251,0],"l":2},"s":{"a":0,"k":[100,100,100],"l":2}},"ao":0,"ef":[{"ty":21,"nm":"Fill","np":9,"en":1,"ef":[{"ty":10,"nm":"Fill Mask","v":{"a":0,"k":0}},{"ty":7,"nm":"All Masks","v":{"a":0,"k":0}},{"ty":2,"nm":"Color","v":{"a":0,"k":[0.078,0.208,0.376,1]}},{"ty":7,"nm":"Invert","v":{"a":0,"k":0}},{"ty":0,"nm":"Horizontal Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Vertical Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Opacity","v":{"a":0,"k":1}}]}],"ip":0,"op":144,"st":0},{"ind":14,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[300,239,0],"l":2},"a":{"a":0,"k":[0,0,0],"l":2},"s":{"a":0,"k":[100,100,100],"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[10.25,40.75]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":20},"nm":"Rectangle Path 1"},{"ty":"fl","c":{"a":0,"k":[0.075,0.086,0.102,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[10.25,40.75]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":20},"nm":"Rectangle Path 1"},{"ty":"fl","c":{"a":0,"k":[0.075,0.086,0.102,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[43.625,-7.375]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[118.182,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle 5"},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[10.25,40.75]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":20},"nm":"Rectangle Path 1"},{"ty":"fl","c":{"a":0,"k":[0.075,0.086,0.102,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[21.875,7.75]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[112.5,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle 4"},{"ty":"tr","p":{"a":0,"k":[-47.375,1.875]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle 4"}],"ip":0,"op":144,"st":0,"ct":1},{"ind":15,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[300,239,0],"l":2},"a":{"a":0,"k":[0,0,0],"l":2},"s":{"a":0,"k":[100,100,100],"l":2}},"ao":0,"ef":[{"ty":21,"nm":"Fill","np":9,"en":1,"ef":[{"ty":10,"nm":"Fill Mask","v":{"a":0,"k":0}},{"ty":7,"nm":"All Masks","v":{"a":0,"k":0}},{"ty":2,"nm":"Color","v":{"a":0,"k":[0.078,0.208,0.376,1]}},{"ty":7,"nm":"Invert","v":{"a":0,"k":0}},{"ty":0,"nm":"Horizontal Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Vertical Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Opacity","v":{"a":0,"k":1}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[10.25,65.75]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":190},"nm":"Rectangle Path 1"},{"ty":"fl","c":{"a":0,"k":[0.078,0.208,0.376,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[-14.625,14.875]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle 3"},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[10.25,40.75]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":20},"nm":"Rectangle Path 1"},{"ty":"fl","c":{"a":0,"k":[0.078,0.208,0.376,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[7.375,17.875]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle 2"},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[10.25,40.75]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":20},"nm":"Rectangle Path 1"},{"ty":"fl","c":{"a":0,"k":[0.078,0.208,0.376,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[-36.625,1.375]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle 1"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-9,-1],[0.928,-15.189],[-9,0],[-5,-18.5],[0,0],[0,0],[0.62,77.498],[-3.875,3.875],[0,0]],"o":[[0,0],[4.275,0.475],[-0.723,11.837],[6.021,0],[2.822,10.442],[0,0],[0,0],[-0.25,-31.25],[17.477,-17.477],[0,0]],"v":[[-48.5,-108.5],[-42.75,-93.25],[-26.928,-78.311],[-15.5,-55.5],[11,-46.5],[12.5,3],[-58,-7.25],[-91,-91],[-85.625,-129.5],[-48.5,-118]],"c":true}},"nm":"Path 1"},{"ty":"fl","c":{"a":0,"k":[0.078,0.208,0.376,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1"}],"ip":0,"op":144,"st":0,"ct":1},{"ind":16,"ty":2,"nm":"Left Hand 2","parent":4,"refId":"image_8","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[-67.142,85.27,0],"l":2},"a":{"a":0,"k":[13.078,27.199,0],"l":2},"s":{"a":0,"k":[100,100,100],"l":2}},"ao":0,"ef":[{"ty":21,"nm":"Fill","np":9,"en":1,"ef":[{"ty":10,"nm":"Fill Mask","v":{"a":0,"k":0}},{"ty":7,"nm":"All Masks","v":{"a":0,"k":0}},{"ty":2,"nm":"Color","v":{"a":0,"k":[0.078,0.208,0.376,1]}},{"ty":7,"nm":"Invert","v":{"a":0,"k":0}},{"ty":0,"nm":"Horizontal Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Vertical Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Opacity","v":{"a":0,"k":1}}]}],"ip":0,"op":144,"st":0},{"ind":17,"ty":2,"nm":"Left Hand","parent":4,"td":1,"refId":"image_8","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[-67.142,85.27,0],"l":2},"a":{"a":0,"k":[13.078,27.199,0],"l":2},"s":{"a":0,"k":[100,100,100],"l":2}},"ao":0,"ef":[{"ty":21,"nm":"Fill","np":9,"en":1,"ef":[{"ty":10,"nm":"Fill Mask","v":{"a":0,"k":0}},{"ty":7,"nm":"All Masks","v":{"a":0,"k":0}},{"ty":2,"nm":"Color","v":{"a":0,"k":[0.078,0.208,0.376,1]}},{"ty":7,"nm":"Invert","v":{"a":0,"k":0}},{"ty":0,"nm":"Horizontal Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Vertical Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Opacity","v":{"a":0,"k":1}}]}],"ip":0,"op":144,"st":0},{"ind":18,"ty":3,"nm":"Null 2","sr":1,"ks":{"o":{"a":0,"k":0},"r":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.281],"y":[0.005]},"t":71,"s":[0]},{"i":{"x":[0.792],"y":[1]},"o":{"x":[0.273],"y":[-0.004]},"t":79,"s":[-7]},{"t":86,"s":[0]}]},"p":{"a":0,"k":[81.125,478.062,0],"l":2},"a":{"a":0,"k":[0,100,0],"l":2},"s":{"a":0,"k":[100,100,100],"l":2}},"ao":0,"ip":0,"op":144,"st":0},{"ind":19,"ty":2,"nm":"Ladder","parent":18,"refId":"image_9","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":1,"k":[{"i":{"x":[0.955],"y":[0.993]},"o":{"x":[0.56],"y":[0]},"t":5,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[1],"y":[-0.001]},"t":68,"s":[6]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":72,"s":[0]},{"t":144,"s":[0]}]},"p":{"a":0,"k":[37.925,98.997,0],"l":2},"a":{"a":0,"k":[39.23,191.848,0],"l":2},"s":{"a":0,"k":[100,100,100],"l":2}},"ao":0,"ef":[{"ty":21,"nm":"Fill","np":9,"en":1,"ef":[{"ty":10,"nm":"Fill Mask","v":{"a":0,"k":0}},{"ty":7,"nm":"All Masks","v":{"a":0,"k":0}},{"ty":2,"nm":"Color","v":{"a":0,"k":[0.016,0.251,0.165,1]}},{"ty":7,"nm":"Invert","v":{"a":0,"k":0}},{"ty":0,"nm":"Horizontal Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Vertical Feather","v":{"a":0,"k":0}},{"ty":0,"nm":"Opacity","v":{"a":0,"k":1}}]}],"ip":0,"op":144,"st":0}]},{"id":"comp_2","nm":"Background Dark","fr":23.976,"layers":[{"ind":1,"ty":4,"nm":"Shape Layer 2","tt":1,"tp":3,"sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[251.5,189.156,0],"l":2},"a":{"a":0,"k":[0,0,0],"l":2},"s":{"a":0,"k":[99.086,99.086,100],"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[215.512,10.226]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":4},"nm":"Rectangle Path 1"},{"ty":"fl","c":{"a":0,"k":[0.106,0.129,0.141,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[104.131,-46.619]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle 8"},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[215.512,10.226]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":4},"nm":"Rectangle Path 1"},{"ty":"fl","c":{"a":0,"k":[0.106,0.129,0.141,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[104.131,-70.354]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle 7"},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[215.512,10.226]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":4},"nm":"Rectangle Path 1"},{"ty":"fl","c":{"a":0,"k":[0.106,0.129,0.141,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[104.131,-94.619]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle 6"},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[215.512,10.226]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":4},"nm":"Rectangle Path 1"},{"ty":"fl","c":{"a":0,"k":[0.106,0.129,0.141,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[104.131,-119.119]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle 5"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[12,0],[8.5,0],[10,0],[8,0],[0,0],[0,0],[0,17.5]],"o":[[-12.5,0],[-8.5,0],[-11.5,0],[0,21],[0,0],[0,0],[-7,0]],"v":[[-130,-108.656],[-162.5,-80.656],[-188,-96.656],[-217.75,-62.656],[-217.5,-24.156],[-97.859,-22.406],[-98,-76.656]],"c":true}},"nm":"Path 1"},{"ty":"fl","c":{"a":0,"k":[0.176,0.2,0.212,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[0,8.771]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1"},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[120,53]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":8},"nm":"Rectangle Path 1"},{"ty":"fl","c":{"a":0,"k":[0.175,0.2,0.21,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[-157.628,30.254]},"a":{"a":0,"k":[0.018,59.947]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle 4"},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[120,120]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":8},"nm":"Rectangle Path 1"},{"ty":"fl","c":{"a":0,"k":[0.149,0.176,0.188,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[-157.777,-63.229]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle 3"},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[15.734,15.734]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1"},{"ty":"fl","c":{"a":0,"k":[0.149,0.176,0.188,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[-218.157,-174.133]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[52.028,52.028]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 3"},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[15.734,15.734]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1"},{"ty":"fl","c":{"a":0,"k":[0.149,0.176,0.188,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[-228.407,-174.133]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[52.028,52.028]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 2"},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[15.734,15.734]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1"},{"ty":"fl","c":{"a":0,"k":[0.149,0.176,0.188,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[-239.157,-174.133]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[52.028,52.028]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 1"},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[511.148,53.09]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":0},"nm":"Rectangle Path 1"},{"ty":"fl","c":{"a":0,"k":[0.106,0.129,0.141,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[-0.541,-175.368]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[101.696,51.394]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle 2"}],"ip":0,"op":144,"st":0,"ct":1},{"ind":2,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[251.5,189,0],"l":2},"a":{"a":0,"k":[0,0,0],"l":2},"s":{"a":0,"k":[99.086,99.086,100],"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[513.957,297.82]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":16},"nm":"Rectangle Path 1"},{"ty":"fl","c":{"a":0,"k":[0.074,0.088,0.102,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[1.963,-39.512]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[99.782,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle 1"}],"ip":0,"op":144,"st":0,"ct":1},{"ind":3,"ty":4,"nm":"Shape Layer 1","td":1,"sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[251.5,189,0],"l":2},"a":{"a":0,"k":[0,0,0],"l":2},"s":{"a":0,"k":[99.086,99.086,100],"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[513.957,297.82]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":16},"nm":"Rectangle Path 1"},{"ty":"fl","c":{"a":0,"k":[0.074,0.088,0.102,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1"},{"ty":"tr","p":{"a":0,"k":[1.963,-39.512]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[99.782,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle 1"}],"ip":0,"op":144,"st":0,"ct":1}]}],"layers":[{"ind":2,"ty":0,"nm":"Character + BG Dark","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[289.5,239,0],"l":2},"a":{"a":0,"k":[350,239,0],"l":2},"s":{"a":0,"k":[100,100,100],"l":2}},"ao":0,"w":700,"h":478,"ip":0,"op":144,"st":0}],"markers":[]} \ No newline at end of file diff --git a/apps/client/src/app/(main)/pages/account/page.tsx b/apps/client/src/app/(main)/pages/account/page.tsx new file mode 100644 index 0000000..f712dd4 --- /dev/null +++ b/apps/client/src/app/(main)/pages/account/page.tsx @@ -0,0 +1,7 @@ +import Account from '../../../../components/sections/account'; + +const Page = () => { + return ; +}; + +export default Page; diff --git a/apps/client/src/app/(main)/pages/coming-soon/page.tsx b/apps/client/src/app/(main)/pages/coming-soon/page.tsx new file mode 100644 index 0000000..d1677dd --- /dev/null +++ b/apps/client/src/app/(main)/pages/coming-soon/page.tsx @@ -0,0 +1,114 @@ +'use client'; + +import Lottie from 'lottie-react'; +import { useTranslation } from 'react-i18next'; +import Box from '@mui/material/Box'; +import Grid from '@mui/material/Grid'; +import Paper from '@mui/material/Paper'; +import Stack from '@mui/material/Stack'; +import Typography from '@mui/material/Typography'; +import bird from 'assets/json/bird.json'; +import bird_dark from 'assets/json/bird_dark.json'; +import charcter from 'assets/json/character.json'; +import charcter_dark from 'assets/json/character_dark.json'; +import { useThemeMode } from 'hooks/useThemeMode'; + +const ComingSoon = () => { + const { t } = useTranslation(); + const { isDark } = useThemeMode(); + return ( + + + + + + + + + + + + {t('coming_soon')}! + + + + + + + + (theme.direction === 'rtl' ? { transform: 'scaleX(-1)' } : {})}> + + + + + + (theme.direction === 'rtl' ? { transform: 'scaleX(-1)' } : {})}> + + + + + + + + + + + + + + + ); +}; + +export default ComingSoon; diff --git a/apps/client/src/components/base/AvatarDropBox.tsx b/apps/client/src/components/base/AvatarDropBox.tsx new file mode 100644 index 0000000..16a85dc --- /dev/null +++ b/apps/client/src/components/base/AvatarDropBox.tsx @@ -0,0 +1,132 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { DropzoneOptions, useDropzone } from 'react-dropzone'; +import { Box, Stack, SxProps, Typography } from '@mui/material'; +import { convertFileToAttachment, getFileNameFromUrl } from 'lib/utils'; +import { FileAttachment } from 'types/common'; +import IconifyIcon from 'components/base/IconifyIcon'; +import Image from './Image'; + +interface AvatarDropBoxProps extends DropzoneOptions { + error?: string; + sx?: SxProps; + defaultFile?: File | string; +} + +const AvatarDropBox = ({ onDrop, error, defaultFile, sx, ...rest }: AvatarDropBoxProps) => { + const [preview, setPreview] = useState(null); + + const { getRootProps, getInputProps } = useDropzone({ + onDrop: (...args) => { + const [acceptedFiles] = args; + if (acceptedFiles.length > 0) { + setPreview(convertFileToAttachment(acceptedFiles[0])); + if (onDrop) { + onDrop(...args); + } + } + }, + multiple: false, + accept: { + 'image/*': ['.jpeg', '.jpg', '.png', '.gif'], + }, + ...rest, + }); + + useEffect(() => { + if (defaultFile) { + if (typeof defaultFile === 'string') { + setPreview({ + name: getFileNameFromUrl(defaultFile), + preview: defaultFile, + format: 'image', + }); + } else { + setPreview(convertFileToAttachment(defaultFile)); + } + } + }, [defaultFile]); + + return ( + + transitions.create(['background-color'], { + duration: transitions.duration.enteringScreen, + easing: transitions.easing.easeInOut, + }), + '&:hover': { + bgcolor: 'background.elevation3', + }, + ...sx, + }} + > + + {preview && ( + {preview?.name} + )} + + + transitions.create(['background-color', 'opacity'], { + duration: transitions.duration.enteringScreen, + easing: transitions.easing.easeInOut, + }), + }, + !!preview?.preview && { + opacity: 0, + '&:hover': { + opacity: 1, + bgcolor: 'rgba(255, 255, 255, 0.8)', + }, + }, + ]} + > + + {!((sx as any)?.width < 100) && Upload Avatar} + + + ); +}; + +export default AvatarDropBox; diff --git a/apps/client/src/components/base/PhoneTextfield.tsx b/apps/client/src/components/base/PhoneTextfield.tsx new file mode 100644 index 0000000..a2362f8 --- /dev/null +++ b/apps/client/src/components/base/PhoneTextfield.tsx @@ -0,0 +1,118 @@ +'use client'; + +import IconifyIcon from './IconifyIcon'; +import { Country } from 'types/countries'; +import NumberTextField from './NumberTextField'; +import React, { useEffect, useState } from 'react'; +import { InputAdornment, Stack } from '@mui/material'; +import { countries as countriesData } from 'data/countries'; +import CountrySelect from 'components/common/CountrySelect'; +import StyledTextField from 'components/styled/StyledTextField'; + +interface PhoneTextfieldProps { + countries?: Country[]; + onChange?: (value: string, event?: React.ChangeEvent) => void; + defaultValue?: { + number: string; + code: string; + }; +} + +const PhoneTextfield = ({ + countries = countriesData, + onChange, + defaultValue, +}: PhoneTextfieldProps) => { + const [country, setCountry] = useState(countries[0]); + const [phoneNo, setPhoneNo] = useState(''); + + useEffect(() => { + if (defaultValue) { + const country = countries.find((country) => country.phone === defaultValue.code); + + setCountry(country || countries[0]); + setPhoneNo(defaultValue.number); + } + }, []); + + return ( + + { + if (value) { + setCountry(value); + } + if (onChange) { + onChange(`(+${value?.phone})${phoneNo}`); + } + }} + options={countries} + value={country} + getOptionLabel={(option) => { + return `+${option.phone}`; + }} + fields={{ flag: true, name: false, phone: true, code: false }} + disableClearable + forcePopupIcon={false} + renderInput={(params) => { + return ( + + + + ) : undefined, + }, + }} + size="large" + /> + ); + }} + slotProps={{ + popper: { + sx: { + '& .MuiAutocomplete-option': { + pl: '8px !important', + pr: '8px !important', + fontSize: 14, + }, + }, + }, + }} + /> + { + setPhoneNo(e.target.value); + if (onChange) { + onChange(`(+${country?.phone})${e.target.value}`, e); + } + }} + /> + + ); +}; + +export default PhoneTextfield; diff --git a/apps/client/src/components/common/CountrySelect.tsx b/apps/client/src/components/common/CountrySelect.tsx new file mode 100644 index 0000000..6678f23 --- /dev/null +++ b/apps/client/src/components/common/CountrySelect.tsx @@ -0,0 +1,62 @@ +import { + Autocomplete, + AutocompleteProps, + AutocompleteRenderInputParams, + Box, + TextField, +} from '@mui/material'; +import { countries } from 'data/countries'; +import { Country } from 'types/countries'; +import IconifyIcon from 'components/base/IconifyIcon'; + +interface CountrySelectProps + extends Omit< + AutocompleteProps, + 'options' | 'renderInput' + > { + fields?: { + flag?: boolean; + name?: boolean; + phone?: boolean; + code?: boolean; + }; + options?: ReadonlyArray; + renderInput?: (params: AutocompleteRenderInputParams) => React.ReactNode; +} + +const CountrySelect = ({ + options = countries, + fields = { flag: true, name: true, phone: false, code: false }, + renderInput = (params) => , + ref, + ...props +}: CountrySelectProps) => { + return ( + option.label} + renderOption={(props, option) => { + const { key, ...optionProps } = props; + return ( + img': { mr: 2, flexShrink: 0 } }} + {...optionProps} + > + {fields?.flag && } + {fields?.name && option.label} {fields?.code && `(${option.code})`}{' '} + {fields?.phone && '+' + option.phone} + + ); + }} + renderInput={renderInput} + {...props} + /> + ); +}; + +export default CountrySelect; diff --git a/apps/client/src/components/sections/account/SideTabList.tsx b/apps/client/src/components/sections/account/SideTabList.tsx new file mode 100644 index 0000000..5ccb133 --- /dev/null +++ b/apps/client/src/components/sections/account/SideTabList.tsx @@ -0,0 +1,128 @@ +'use client'; + +import { Dispatch, SetStateAction, SyntheticEvent, useEffect } from 'react'; +import { TabList } from '@mui/lab'; +import { InputAdornment, PaperProps, Stack, SxProps, tabsClasses, Typography } from '@mui/material'; +import { accountTabs } from 'data/account/account-tabs'; +import { useBreakpoints } from 'providers/BreakpointsProvider'; +import IconifyIcon from 'components/base/IconifyIcon'; +import StyledTextField from 'components/styled/StyledTextField'; +import AccountTab from './common/AccountTab'; + +interface SideTabListProps extends PaperProps { + setShowTabList: Dispatch>; + handleChange: (event: SyntheticEvent, newValue: string) => void; + sx?: SxProps; +} + +const SideTabList = ({ setShowTabList, handleChange, sx }: SideTabListProps) => { + const { down, currentBreakpoint } = useBreakpoints(); + + const downMd = down('md'); + + useEffect(() => { + if (!downMd) { + setShowTabList(false); + } + }, [downMd]); + + return ( + + + + Account Settings + + + + + + ), + }, + }} + sx={{ maxWidth: { xs: 1, sm: 0.5, md: 1 } }} + /> + + + {accountTabs.map((tab) => ( + + } + label={ + + {tab.label} + + } + onClick={() => { + if (downMd) { + setShowTabList(false); + } + window.scrollTo(0, 0); + }} + sx={{ + maxWidth: 'none', + '&:hover': { bgcolor: 'background.elevation3' }, + }} + /> + ))} + + + + ); +}; + +export default SideTabList; diff --git a/apps/client/src/components/sections/account/common/AccountDialog.tsx b/apps/client/src/components/sections/account/common/AccountDialog.tsx new file mode 100644 index 0000000..ea75164 --- /dev/null +++ b/apps/client/src/components/sections/account/common/AccountDialog.tsx @@ -0,0 +1,80 @@ +import { ReactNode } from 'react'; +import { + Button, + Dialog, + IconButton, + DialogTitle, + DialogActions, + DialogContent, + DialogContentText, + DialogProps, + dialogClasses, +} from '@mui/material'; +import IconifyIcon from 'components/base/IconifyIcon'; + +interface AccountDialogProps extends DialogProps { + handleDialogClose: () => void; + subtitle?: ReactNode; + handleConfirm?: () => void; + handleDiscard?: () => void; +} + +const AccountDialog = (props: AccountDialogProps) => { + const { title, subtitle, children, sx, open, handleDialogClose, handleConfirm, handleDiscard } = + props; + + return ( + + + {title} + + + + + + {subtitle && ( + + {subtitle} + + )} + {children} + + + + + + + ); +}; + +export default AccountDialog; diff --git a/apps/client/src/components/sections/account/common/AccountFormDialog.tsx b/apps/client/src/components/sections/account/common/AccountFormDialog.tsx new file mode 100644 index 0000000..29c45ee --- /dev/null +++ b/apps/client/src/components/sections/account/common/AccountFormDialog.tsx @@ -0,0 +1,115 @@ +import { ReactNode } from 'react'; +import { useFormContext } from 'react-hook-form'; +import { + Button, + Dialog, + IconButton, + DialogTitle, + DialogActions, + DialogContent, + DialogContentText, + DialogProps, + dialogClasses, +} from '@mui/material'; +import IconifyIcon from 'components/base/IconifyIcon'; + +interface AccountFormDialogProps extends DialogProps { + handleDialogClose: () => void; + subtitle?: ReactNode; + onSubmit: (data: any) => void; + handleDiscard?: () => void; + handleRemove?: () => void; +} + +const AccountFormDialog = (props: AccountFormDialogProps) => { + const { + open, + handleDialogClose, + title, + subtitle, + onSubmit, + handleDiscard, + handleRemove, + children, + sx, + } = props; + + const { handleSubmit, reset } = useFormContext(); + + return ( + + + {title} + + + + + + {subtitle && ( + + {subtitle} + + )} + {children} + + + {handleRemove && ( + + )} + + + + + ); +}; + +export default AccountFormDialog; diff --git a/apps/client/src/components/sections/account/common/AccountTab.tsx b/apps/client/src/components/sections/account/common/AccountTab.tsx new file mode 100644 index 0000000..ca7a0be --- /dev/null +++ b/apps/client/src/components/sections/account/common/AccountTab.tsx @@ -0,0 +1,35 @@ +import { MouseEventHandler } from 'react'; +import { Tab, tabClasses, TabOwnProps } from '@mui/material'; + +interface AccountTabProps extends TabOwnProps { + onClick?: MouseEventHandler | undefined; +} +const AccountTab = (props: AccountTabProps) => { + return ( + + ); +}; + +export default AccountTab; diff --git a/apps/client/src/components/sections/account/common/AccountTabPanel.tsx b/apps/client/src/components/sections/account/common/AccountTabPanel.tsx new file mode 100644 index 0000000..6b171ab --- /dev/null +++ b/apps/client/src/components/sections/account/common/AccountTabPanel.tsx @@ -0,0 +1,56 @@ +import { ReactElement, PropsWithChildren } from 'react'; +import { TabPanel } from '@mui/lab'; +import { IconButton, Stack, Typography } from '@mui/material'; +import IconifyIcon from 'components/base/IconifyIcon'; + +interface AccountTabPanelProps { + label: string; + title: string; + value: string; + panelIcon: string; + setShowTabList: (value: boolean) => void; +} + +const AccountTabPanel = ({ + title, + value, + panelIcon, + setShowTabList, + children, +}: PropsWithChildren): ReactElement => { + return ( + + + setShowTabList(true)} sx={{ display: { md: 'none' }, ml: -1.5 }}> + + + + + + {title} + + + {children} + + ); +}; + +export default AccountTabPanel; diff --git a/apps/client/src/components/sections/account/common/AccountTabPanelSection.tsx b/apps/client/src/components/sections/account/common/AccountTabPanelSection.tsx new file mode 100644 index 0000000..59996aa --- /dev/null +++ b/apps/client/src/components/sections/account/common/AccountTabPanelSection.tsx @@ -0,0 +1,46 @@ +import { ReactElement, PropsWithChildren } from 'react'; +import { Box, Stack, SxProps, Typography } from '@mui/material'; +import IconifyIcon from 'components/base/IconifyIcon'; + +interface AccountTabPanelSectionProps { + title: string; + subtitle?: string; + subtitleEl?: ReactElement; + icon: string; + sx?: SxProps; + actionComponent?: ReactElement; +} + +const AccountTabPanelSection = ({ + title, + subtitle, + subtitleEl, + icon, + children, + sx, + actionComponent, +}: PropsWithChildren) => { + return ( + + + + + {title} + + {actionComponent} + + {subtitle && ( + + {subtitle} + + )} + {subtitleEl} + {children} + + ); +}; + +export default AccountTabPanelSection; diff --git a/apps/client/src/components/sections/account/common/InfoCard.tsx b/apps/client/src/components/sections/account/common/InfoCard.tsx new file mode 100644 index 0000000..9cd9971 --- /dev/null +++ b/apps/client/src/components/sections/account/common/InfoCard.tsx @@ -0,0 +1,56 @@ +import { Dispatch, PropsWithChildren, SetStateAction } from 'react'; +import { Paper, PaperProps } from '@mui/material'; + +interface InfoCardProps extends PaperProps { + setOpen?: Dispatch> | null; + onClick?: () => void; +} + +const InfoCard = ({ + sx, + setOpen, + onClick, + children, + ...props +}: PropsWithChildren) => { + return ( + { + if (setOpen) { + setOpen(true); + } else { + onClick?.(); + } + }} + sx={{ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'flex-start', + px: 3, + py: 2, + border: '0 !important', + ...sx, + ...(setOpen || onClick + ? { + '&:hover': { + cursor: 'pointer', + bgcolor: 'background.elevation2', + '& .iconify': { + visibility: 'visible', + }, + }, + } + : {}), + }} + > + {children} + + ); +}; + +export default InfoCard; diff --git a/apps/client/src/components/sections/account/common/InfoCardAttribute.tsx b/apps/client/src/components/sections/account/common/InfoCardAttribute.tsx new file mode 100644 index 0000000..f4a84b0 --- /dev/null +++ b/apps/client/src/components/sections/account/common/InfoCardAttribute.tsx @@ -0,0 +1,21 @@ +import { Stack, Typography } from '@mui/material'; + +interface InfoCardAttributeProps { + label: string; + value: string; +} + +const InfoCardAttribute = ({ label, value }: InfoCardAttributeProps) => { + return ( + + + {label} + + + {value} + + + ); +}; + +export default InfoCardAttribute; diff --git a/apps/client/src/components/sections/account/index.tsx b/apps/client/src/components/sections/account/index.tsx new file mode 100644 index 0000000..141a0ff --- /dev/null +++ b/apps/client/src/components/sections/account/index.tsx @@ -0,0 +1,108 @@ +'use client'; + +import { SyntheticEvent, useState } from 'react'; +import { TabContext } from '@mui/lab'; +import { Container, Drawer, Paper, Stack } from '@mui/material'; +import { accountTabs } from '../../../data/account/account-tabs'; +import { useNavContext } from 'layouts/main-layout/NavProvider'; +import { useBreakpoints } from 'providers/BreakpointsProvider'; +import { useSettingsContext } from 'providers/SettingsProvider'; +import SimpleBar from 'components/base/SimpleBar'; +import SideTabList from 'components/sections/account/SideTabList'; +import AccountTabPanel from 'components/sections/account/common/AccountTabPanel'; +import AccountsProvider from 'providers/AccountsProvider'; + +const Account = () => { + const [activeTab, setActiveTab] = useState(accountTabs[0].value); + const { down } = useBreakpoints(); + const [showTabList, setShowTabList] = useState(true); + const { + config: { textDirection }, + } = useSettingsContext(); + const { topbarHeight } = useNavContext(); + + const downMd = down('md'); + const handleChange = (_event: SyntheticEvent, newValue: string): void => setActiveTab(newValue); + + return ( + + + + {downMd ? ( + setShowTabList(false)} + ModalProps={{ + keepMounted: true, + disablePortal: true, + }} + slotProps={{ + paper: { + sx: { + bgcolor: 'background.elevation1', + width: 1, + overflow: 'hidden', + pointerEvents: 'auto', + height: ({ mixins }) => mixins.contentHeight(topbarHeight), + top: ({ mixins }) => mixins.topOffset(topbarHeight, 1), + }, + }, + }} + sx={{ + pointerEvents: 'none', + }} + > + + + + + ) : ( + mixins.topOffset(topbarHeight), + height: ({ mixins }) => mixins.contentHeight(topbarHeight), + }} + > + + + + + )} + + + + {accountTabs.map((tab) => ( + + {tab.tabPanel} + + ))} + + + + + + ); +}; + +export default Account; diff --git a/apps/client/src/components/sections/account/personal-info/Address.tsx b/apps/client/src/components/sections/account/personal-info/Address.tsx new file mode 100644 index 0000000..e9f2f1d --- /dev/null +++ b/apps/client/src/components/sections/account/personal-info/Address.tsx @@ -0,0 +1,188 @@ +import { useState } from 'react'; +import { useForm, Controller, FormProvider, SubmitHandler } from 'react-hook-form'; +import { yupResolver } from '@hookform/resolvers/yup'; +import { + Radio, + Stack, + TextField, + RadioGroup, + Typography, + FormControl, + FormControlLabel, +} from '@mui/material'; +import { countries } from 'data/countries'; +import { useSnackbar } from 'notistack'; +import { useAccounts } from 'providers/AccountsProvider'; +import { useBreakpoints } from 'providers/BreakpointsProvider'; +import * as yup from 'yup'; +import IconifyIcon from 'components/base/IconifyIcon'; +import CountrySelect from 'components/common/CountrySelect'; +import AccountFormDialog from '../common/AccountFormDialog'; +import InfoCard from '../common/InfoCard'; +import InfoCardAttribute from '../common/InfoCardAttribute'; + +export interface AddressFormValues { + country: string; + state: string; + city: string; + street: string; + zip: string; + visibility?: 'only_me' | 'followers_only' | 'everyone'; +} + +const addressSchema = yup.object().shape({ + country: yup.string().required('Country name is required'), + state: yup.string().required('State name is required'), + city: yup.string().required('City name is required'), + street: yup.string().required('Street name is required'), + zip: yup.string().required('ZIP is required'), +}); + +const Address = () => { + const [open, setOpen] = useState(false); + const { personalInfo } = useAccounts(); + const { up } = useBreakpoints(); + const { enqueueSnackbar } = useSnackbar(); + const [currentAddress, setCurrentAddress] = useState({ + country: personalInfo.country, + state: personalInfo.state, + city: personalInfo.city, + street: personalInfo.street, + zip: personalInfo.zip, + }); + const methods = useForm({ + defaultValues: { + country: currentAddress.country, + state: currentAddress.state, + city: currentAddress.city, + street: currentAddress.street, + zip: currentAddress.zip, + visibility: 'followers_only', + }, + resolver: yupResolver(addressSchema), + }); + const { + control, + getValues, + reset, + register, + formState: { errors }, + } = methods; + + const upSm = up('sm'); + + const onSubmit: SubmitHandler = (data) => { + console.log(data); + const updatedData = getValues(); + setCurrentAddress(updatedData); + setOpen(false); + enqueueSnackbar('Updated successfully!', { variant: 'success', autoHideDuration: 3000 }); + }; + + const handleDiscard = () => { + reset(currentAddress); + setOpen(false); + }; + + return ( + + + + + + + + + + + + setOpen(false)} + handleDiscard={handleDiscard} + sx={{ + maxWidth: 463, + }} + > + + ( + onChange(value ? value.label : '')} + value={countries.find((country) => country.label === value) || null} + renderInput={(params) => ( + + )} + /> + )} + /> + + + + + + + + + Who can see your address? + + ( + + } label="Only me" /> + } label="Followers only" /> + } label="Everyone" /> + + )} + /> + + + ); +}; + +export default Address; diff --git a/apps/client/src/components/sections/account/personal-info/Birthday.tsx b/apps/client/src/components/sections/account/personal-info/Birthday.tsx new file mode 100644 index 0000000..57a3781 --- /dev/null +++ b/apps/client/src/components/sections/account/personal-info/Birthday.tsx @@ -0,0 +1,125 @@ +import { useState } from 'react'; +import { useForm, Controller, FormProvider, SubmitHandler } from 'react-hook-form'; +import { yupResolver } from '@hookform/resolvers/yup'; +import { Radio, Stack, RadioGroup, Typography, FormControl, FormControlLabel } from '@mui/material'; +import { DatePicker } from '@mui/x-date-pickers/DatePicker'; +import dayjs from 'dayjs'; +import { useSnackbar } from 'notistack'; +import { useAccounts } from 'providers/AccountsProvider'; +import { useBreakpoints } from 'providers/BreakpointsProvider'; +import * as yup from 'yup'; +import IconifyIcon from 'components/base/IconifyIcon'; +import AccountFormDialog from '../common/AccountFormDialog'; +import InfoCard from '../common/InfoCard'; +import InfoCardAttribute from '../common/InfoCardAttribute'; + +export interface BirthdayFormValues { + birthDate: string; + visibility?: 'only_me' | 'followers_only' | 'everyone'; +} + +const birthdaySchema = yup.object().shape({ + birthDate: yup.string().required('Birth date is required'), +}); + +const Birthday = () => { + const [open, setOpen] = useState(false); + const { personalInfo } = useAccounts(); + const { up } = useBreakpoints(); + const { enqueueSnackbar } = useSnackbar(); + const [currentBirthDate, setCurrentBirthDate] = useState(personalInfo.birthDate); + const methods = useForm({ + defaultValues: { + birthDate: currentBirthDate, + visibility: 'only_me', + }, + resolver: yupResolver(birthdaySchema), + }); + const { + control, + reset, + getValues, + formState: { errors }, + } = methods; + + const upSm = up('sm'); + + const onSubmit: SubmitHandler = (data) => { + console.log(data); + const updatedData = getValues(); + setCurrentBirthDate(updatedData.birthDate); + setOpen(false); + enqueueSnackbar('Updated successfully!', { variant: 'success', autoHideDuration: 3000 }); + }; + const handleDiscard = () => { + reset({ birthDate: currentBirthDate }); + setOpen(false); + }; + + return ( + + + + + + + + setOpen(false)} + handleDiscard={handleDiscard} + sx={{ + maxWidth: 463, + }} + > + + ( + + )} + /> + + + + + Who can see your birthday? + + ( + + } label="Only me" /> + } label="Followers only" /> + } label="Everyone" /> + + )} + /> + + + ); +}; + +export default Birthday; diff --git a/apps/client/src/components/sections/account/personal-info/Email.tsx b/apps/client/src/components/sections/account/personal-info/Email.tsx new file mode 100644 index 0000000..9af4b38 --- /dev/null +++ b/apps/client/src/components/sections/account/personal-info/Email.tsx @@ -0,0 +1,117 @@ +import { useState } from 'react'; +import { useForm, FormProvider, SubmitHandler } from 'react-hook-form'; +import { yupResolver } from '@hookform/resolvers/yup'; +import { Stack, TextField, Typography } from '@mui/material'; +import { useSnackbar } from 'notistack'; +import { useAccounts } from 'providers/AccountsProvider'; +import * as yup from 'yup'; +import IconifyIcon from 'components/base/IconifyIcon'; +import AccountFormDialog from '../common/AccountFormDialog'; +import InfoCard from '../common/InfoCard'; +import InfoCardAttribute from '../common/InfoCardAttribute'; + +interface EmailFormValues { + primaryEmail: string; + secondaryEmail: string; +} + +const emailSchema = yup.object().shape({ + primaryEmail: yup + .string() + .email('Primary email must be a valid email') + .required('Primary email is required'), + secondaryEmail: yup + .string() + .email('Secondary email must be a valid email') + .required('Secondary email is required'), +}); + +const Email = () => { + const [open, setOpen] = useState(false); + const { personalInfo } = useAccounts(); + const { enqueueSnackbar } = useSnackbar(); + const [currentEmail, setCurrentEmail] = useState({ + primaryEmail: personalInfo.primaryEmail, + secondaryEmail: personalInfo.secondaryEmail, + }); + const methods = useForm({ + defaultValues: { + primaryEmail: personalInfo.primaryEmail, + secondaryEmail: personalInfo.secondaryEmail, + }, + resolver: yupResolver(emailSchema), + }); + const { + getValues, + register, + reset, + formState: { errors }, + } = methods; + + const onSubmit: SubmitHandler = (data) => { + console.log(data); + const updatedData = getValues(); + setCurrentEmail(updatedData); + setOpen(false); + enqueueSnackbar('Updated successfully!', { variant: 'success', autoHideDuration: 3000 }); + }; + + const handleDiscard = () => { + reset(currentEmail); + setOpen(false); + }; + + return ( + + + + + + + + + setOpen(false)} + handleDiscard={handleDiscard} + sx={{ + maxWidth: 463, + }} + > + + + + + + + + + Your alternate email will be used to gain access to your account if you ever have issues + with logging in with your primary email. + + + + ); +}; + +export default Email; diff --git a/apps/client/src/components/sections/account/personal-info/Names.tsx b/apps/client/src/components/sections/account/personal-info/Names.tsx new file mode 100644 index 0000000..8a67258 --- /dev/null +++ b/apps/client/src/components/sections/account/personal-info/Names.tsx @@ -0,0 +1,102 @@ +import { useState } from 'react'; +import { useForm, FormProvider, SubmitHandler } from 'react-hook-form'; +import { yupResolver } from '@hookform/resolvers/yup'; +import { Stack, TextField } from '@mui/material'; +import { useSnackbar } from 'notistack'; +import { useAccounts } from 'providers/AccountsProvider'; +import * as yup from 'yup'; +import IconifyIcon from 'components/base/IconifyIcon'; +import AccountFormDialog from '../common/AccountFormDialog'; +import InfoCard from '../common/InfoCard'; +import InfoCardAttribute from '../common/InfoCardAttribute'; + +interface NameFormValues { + firstName: string; + lastName: string; +} + +const nameSchema = yup.object().shape({ + firstName: yup.string().required('First name is required'), + lastName: yup.string().required('Last name is required'), +}); + +const Names = () => { + const { personalInfo } = useAccounts(); + const [open, setOpen] = useState(false); + const { enqueueSnackbar } = useSnackbar(); + const [currentName, setCurrentName] = useState({ + firstName: personalInfo.firstName, + lastName: personalInfo.lastName, + }); + const methods = useForm({ + defaultValues: { + firstName: currentName.firstName, + lastName: currentName.lastName, + }, + resolver: yupResolver(nameSchema), + }); + const { + register, + getValues, + reset, + formState: { errors }, + } = methods; + + const onSubmit: SubmitHandler = (data) => { + console.log(data); + const updatedData = getValues(); + setCurrentName(updatedData); + setOpen(false); + enqueueSnackbar('Updated successfully!', { variant: 'success', autoHideDuration: 3000 }); + }; + + const handleDiscard = () => { + reset({ firstName: currentName.firstName, lastName: currentName.lastName }); + setOpen(false); + }; + + return ( + + + + + + + + + setOpen(false)} + handleDiscard={handleDiscard} + sx={{ maxWidth: 463 }} + > + + + + + + + ); +}; + +export default Names; diff --git a/apps/client/src/components/sections/account/personal-info/PersonalInfoTabPanel.tsx b/apps/client/src/components/sections/account/personal-info/PersonalInfoTabPanel.tsx new file mode 100644 index 0000000..95cd760 --- /dev/null +++ b/apps/client/src/components/sections/account/personal-info/PersonalInfoTabPanel.tsx @@ -0,0 +1,69 @@ +import { Stack, Divider } from '@mui/material'; +import AvatarDropBox from 'components/base/AvatarDropBox'; +import AccountTabPanelSection from '../common/AccountTabPanelSection'; +import Address from './Address'; +import Birthday from './Birthday'; +import Email from './Email'; +import Names from './Names'; +import Phone from './Phone'; +import UserName from './UserName'; + +const PersonalInfoTabPanel = () => { + return ( + <> + + { + console.log({ acceptedFiles }); + }} + /> + + } spacing={5}> + + + + + + + + + + + + +
+ + + + + + + + + + + + ); +}; + +export default PersonalInfoTabPanel; diff --git a/apps/client/src/components/sections/account/personal-info/Phone.tsx b/apps/client/src/components/sections/account/personal-info/Phone.tsx new file mode 100644 index 0000000..84fc73c --- /dev/null +++ b/apps/client/src/components/sections/account/personal-info/Phone.tsx @@ -0,0 +1,107 @@ +import { useState } from 'react'; +import { Controller, FormProvider, SubmitHandler, useForm } from 'react-hook-form'; +import { yupResolver } from '@hookform/resolvers/yup'; +import { Link, Stack, Typography } from '@mui/material'; +import { useSnackbar } from 'notistack'; +import { useAccounts } from 'providers/AccountsProvider'; +import * as yup from 'yup'; +import IconifyIcon from 'components/base/IconifyIcon'; +import PhoneTextfield from 'components/base/PhoneTextfield'; +import AccountFormDialog from '../common/AccountFormDialog'; +import InfoCard from '../common/InfoCard'; +import InfoCardAttribute from '../common/InfoCardAttribute'; + +interface PhoneFormValues { + phoneNumber: string; +} + +const phoneSchema = yup + .object({ + phoneNumber: yup.string().required('Phone number is required'), + }) + .required(); + +const Phone = () => { + const [open, setOpen] = useState(false); + const { personalInfo } = useAccounts(); + const { enqueueSnackbar } = useSnackbar(); + const [currentPhone, setCurrentPhone] = useState(personalInfo.phoneNumber); + const methods = useForm({ + defaultValues: { + phoneNumber: currentPhone, + }, + resolver: yupResolver(phoneSchema), + }); + const { control, reset, getValues } = methods; + + const onSubmit: SubmitHandler = (data) => { + console.log(data); + const updatedData = getValues(); + setCurrentPhone(updatedData.phoneNumber); + setOpen(false); + enqueueSnackbar('Updated successfully!', { variant: 'success', autoHideDuration: 3000 }); + }; + const handleDiscard = () => { + reset({ phoneNumber: currentPhone }); + setOpen(false); + }; + const match = currentPhone.match(/\(\+(\d+)\)(\d+)/); + + return ( + + + + + + + + setOpen(false)} + handleDiscard={handleDiscard} + sx={{ + maxWidth: 463, + }} + > + ( + + )} + /> + + + + This phone number has to be confirmed to ensure its authenticity first before being + connected with your profile. + + + Confirm your number{' '} + + + + + ); +}; + +export default Phone; diff --git a/apps/client/src/components/sections/account/personal-info/UserName.tsx b/apps/client/src/components/sections/account/personal-info/UserName.tsx new file mode 100644 index 0000000..aa9bdcf --- /dev/null +++ b/apps/client/src/components/sections/account/personal-info/UserName.tsx @@ -0,0 +1,89 @@ +import { useState } from 'react'; +import { useForm, FormProvider, SubmitHandler } from 'react-hook-form'; +import { yupResolver } from '@hookform/resolvers/yup'; +import { Stack, TextField } from '@mui/material'; +import { useSnackbar } from 'notistack'; +import { useAccounts } from 'providers/AccountsProvider'; +import * as yup from 'yup'; +import IconifyIcon from 'components/base/IconifyIcon'; +import AccountFormDialog from '../common/AccountFormDialog'; +import InfoCard from '../common/InfoCard'; +import InfoCardAttribute from '../common/InfoCardAttribute'; + +interface UserNameFormValues { + userName: string; +} + +const userNameSchema = yup.object().shape({ + userName: yup.string().required('User name is required'), +}); + +const UserName = () => { + const { personalInfo } = useAccounts(); + const [open, setOpen] = useState(false); + const { enqueueSnackbar } = useSnackbar(); + const [currentUserName, setCurrentUserName] = useState(personalInfo.userName); + const methods = useForm({ + defaultValues: { + userName: currentUserName, + }, + resolver: yupResolver(userNameSchema), + }); + const { + register, + getValues, + reset, + formState: { errors }, + } = methods; + + const onSubmit: SubmitHandler = (data) => { + console.log(data); + const updatedData = getValues(); + setCurrentUserName(updatedData.userName); + setOpen(false); + enqueueSnackbar('Updated successfully!', { variant: 'success', autoHideDuration: 3000 }); + }; + + const handleDiscard = () => { + reset({ userName: currentUserName }); + setOpen(false); + }; + + return ( + + + + + + + + setOpen(false)} + handleDiscard={handleDiscard} + sx={{ + maxWidth: 463, + }} + > + + + + + + ); +}; + +export default UserName; diff --git a/apps/client/src/components/sections/account/touch-id/Biometrics.tsx b/apps/client/src/components/sections/account/touch-id/Biometrics.tsx new file mode 100644 index 0000000..ef42d7b --- /dev/null +++ b/apps/client/src/components/sections/account/touch-id/Biometrics.tsx @@ -0,0 +1,296 @@ +import { authClient } from '@/auth'; +import InfoCard from '../common/InfoCard'; +import { useState, useEffect } from 'react'; +import IconifyIcon from 'components/base/IconifyIcon'; +import PasskeySetupDialog from './PasskeySetupDialog'; +import { Alert, Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Stack, TextField, Typography } from '@mui/material'; + +const Biometrics = () => { + const [open, setOpen] = useState(false); + const [passkeys, setPasskeys] = useState([]); + const [loading, setLoading] = useState(true); + const [confirmDialogOpen, setConfirmDialogOpen] = useState(false); + const [passkeyToDelete, setPasskeyToDelete] = useState(null); + const [isDeleting, setIsDeleting] = useState(false); + const [editDialogOpen, setEditDialogOpen] = useState(false); + const [passkeyToEdit, setPasskeyToEdit] = useState<{ id: string; name: string } | null>(null); + const [newPasskeyName, setNewPasskeyName] = useState(""); + const [isUpdating, setIsUpdating] = useState(false); + const [updateError, setUpdateError] = useState(""); + + const fetchPasskeys = async () => { + try { + const { data, error } = await authClient.passkey.listUserPasskeys(); + if (error) { + console.error('Error fetching passkeys:', error); + } else if (data) { + setPasskeys(data); + } + } catch (err) { + console.error('Failed to fetch passkeys:', err); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + fetchPasskeys(); + }, []); + + const handleDeletePasskey = async (passkeyId: string) => { + setPasskeyToDelete(passkeyId); + setConfirmDialogOpen(true); + }; + + const confirmDelete = async () => { + if (!passkeyToDelete) return; + + setIsDeleting(true); + try { + const { data, error } = await authClient.passkey.deletePasskey({ + id: passkeyToDelete, + }); + + if (error) { + console.error('Error deleting passkey:', error); + } else { + setPasskeys((prev) => prev.filter((pk) => pk.id !== passkeyToDelete)); + } + } catch (err) { + console.error('Failed to delete passkey:', err); + } finally { + setIsDeleting(false); + setConfirmDialogOpen(false); + setPasskeyToDelete(null); + } + }; + + const handleEditPasskey = (passkeyId: string, currentName: string) => { + setPasskeyToEdit({ id: passkeyId, name: currentName }); + setNewPasskeyName(currentName); + setEditDialogOpen(true); + setUpdateError(""); + }; + + const confirmUpdate = async () => { + if (!passkeyToEdit || !newPasskeyName.trim()) { + setUpdateError("Passkey name is required"); + return; + } + + setIsUpdating(true); + setUpdateError(""); + + try { + const { error } = await authClient.passkey.updatePasskey({ + id: passkeyToEdit.id, + name: newPasskeyName.trim(), + }); + + if (error) { + setUpdateError(error.message || "Failed to update passkey"); + } else { + // Refetch passkeys to sync with server + await fetchPasskeys(); + setEditDialogOpen(false); + setPasskeyToEdit(null); + setNewPasskeyName(""); + } + } catch (err) { + setUpdateError("An unexpected error occurred"); + } finally { + setIsUpdating(false); + } + }; + + const handlePasskeySuccess = () => { + fetchPasskeys(); + }; + + return ( + <> + + + Manage Passkey Features + + + {loading ? ( + Loading... + ) : passkeys.length > 0 ? ( + passkeys.map((passkey, index) => ( + + + + + {passkey.name || `Fingerprint ${index + 1}`} + + + + { + e.stopPropagation(); + handleEditPasskey(passkey.id, passkey.name || `Fingerprint ${index + 1}`); + }} + /> + { + e.stopPropagation(); + handleDeletePasskey(passkey.id); + }} + /> + + + )) + ) : ( + No passkeys found + )} + + {passkeys.length < 1 && ( + + )} + + + setOpen(false)} + onSuccess={handlePasskeySuccess} + /> + + { + setEditDialogOpen(false); + setPasskeyToEdit(null); + setNewPasskeyName(""); + setUpdateError(""); + }} + maxWidth="sm" + fullWidth + > + Edit Passkey Name + + {updateError && ( + + {updateError} + + )} + { + setNewPasskeyName(e.target.value); + if (updateError === "Passkey name is required") { + setUpdateError(""); + } + }} + variant="outlined" + sx={{ mt: 1 }} + error={updateError === "Passkey name is required"} + /> + + + + + + + + setConfirmDialogOpen(false)} + sx={{ + '& .MuiDialog-paper': { + width: 450, + }, + }} + > + + Are you sure to delete? + + + + This action cannot be undone. You will need to set up a new passkey if you want to use this feature again. + + + + + + + + + ); +}; + +export default Biometrics; diff --git a/apps/client/src/components/sections/account/touch-id/PasskeySetupDialog.tsx b/apps/client/src/components/sections/account/touch-id/PasskeySetupDialog.tsx new file mode 100644 index 0000000..e0d9e10 --- /dev/null +++ b/apps/client/src/components/sections/account/touch-id/PasskeySetupDialog.tsx @@ -0,0 +1,166 @@ +import { useState } from 'react'; +import { authClient } from '@/auth'; +import IconifyIcon from 'components/base/IconifyIcon'; +import { + Alert, + Button, + Dialog, + DialogActions, + DialogContent, + DialogContentText, + DialogTitle, + FormControl, + FormControlLabel, + FormLabel, + Radio, + RadioGroup, + Stack, + TextField, + Typography, +} from '@mui/material'; + +interface PasskeySetupDialogProps { + open: boolean; + onClose: () => void; + onSuccess?: () => void; +} + +const PasskeySetupDialog = ({ open, onClose, onSuccess }: PasskeySetupDialogProps) => { + const [passkeyName, setPasskeyName] = useState(""); + const [passkeyError, setPasskeyError] = useState(""); + const [isAddingPasskey, setIsAddingPasskey] = useState(false); + const [authenticatorType, setAuthenticatorType] = useState<"platform" | "cross-platform">("platform"); + + const handleAddPasskey = async () => { + if (!passkeyName.trim()) { + setPasskeyError("Passkey name is required"); + return; + } + + setIsAddingPasskey(true); + setPasskeyError(""); + + try { + const response = await authClient.passkey.addPasskey({ + name: passkeyName.trim(), + authenticatorAttachment: authenticatorType, + }); + + if (response?.error) { + setPasskeyError(response.error.message || "Failed to add passkey"); + } else { + setPasskeyName(""); + setAuthenticatorType("platform"); + onSuccess?.(); + onClose(); + } + } catch (err) { + setPasskeyError("An unexpected error occurred"); + } finally { + setIsAddingPasskey(false); + } + }; + + const handleClose = () => { + setPasskeyName(""); + setPasskeyError(""); + setAuthenticatorType("platform"); + onClose(); + }; + + return ( + + + + + Set Up Passkey + + + + + Enhance your account security with a passkey. Use your fingerprint or device PIN for quick and secure access. + + + {passkeyError && ( + + {passkeyError} + + )} + + { + setPasskeyName(e.target.value); + if (passkeyError === "Passkey name is required") { + setPasskeyError(""); + } + }} + sx={{ mb: 3 }} + variant="outlined" + error={passkeyError === "Passkey name is required"} + /> + + + + Authentication Method + + setAuthenticatorType(e.target.value as "platform" | "cross-platform")} + > + } + label={ + + + + This Device + + + (Use biometrics or PIN on this device) + + + } + /> + } + label={ + + + + Security Key + + + (Use a USB security key or another device) + + + } + /> + + + + + + + + + ); +}; + +export default PasskeySetupDialog; diff --git a/apps/client/src/components/sections/account/touch-id/TouchIdTabPanel.tsx b/apps/client/src/components/sections/account/touch-id/TouchIdTabPanel.tsx new file mode 100644 index 0000000..318b124 --- /dev/null +++ b/apps/client/src/components/sections/account/touch-id/TouchIdTabPanel.tsx @@ -0,0 +1,27 @@ +import { Divider, Stack } from '@mui/material'; +import AccountTabPanelSection from '../common/AccountTabPanelSection'; +import Biometrics from './Biometrics'; +import TwoFactorFeatures from './TwoFactorFeatures'; + +const TouchIDTabPanel = () => { + return ( + } spacing={5}> + + + + + + + + ); +}; + +export default TouchIDTabPanel; diff --git a/apps/client/src/components/sections/account/touch-id/TwoFactorFeatures.tsx b/apps/client/src/components/sections/account/touch-id/TwoFactorFeatures.tsx new file mode 100644 index 0000000..dac74f9 --- /dev/null +++ b/apps/client/src/components/sections/account/touch-id/TwoFactorFeatures.tsx @@ -0,0 +1,278 @@ +import { authClient } from '@/auth'; +import { useState, useEffect } from 'react'; +import { FormControl, FormControlLabel, Stack, Switch, Typography, Dialog, DialogTitle, DialogContent, DialogActions, Button, TextField, Alert, CircularProgress, Box } from '@mui/material'; +import QRCode from "react-qr-code"; + +const TwoFactorFeatures = () => { + const [twoFactorEnabled, setTwoFactorEnabled] = useState(false); + const [loading, setLoading] = useState(false); + const [openPasswordDialog, setOpenPasswordDialog] = useState(false); + const [openQRDialog, setOpenQRDialog] = useState(false); + const [dialogMode, setDialogMode] = useState<'enable' | 'disable'>('enable'); + const [password, setPassword] = useState(''); + const [totpCode, setTotpCode] = useState(''); + const [totpURI, setTotpURI] = useState(''); + const [error, setError] = useState(''); + + useEffect(() => { + const fetchUser = async () => { + try { + const { data } = await authClient.getSession(); + setTwoFactorEnabled(data?.user?.twoFactorEnabled || false); + } catch (err) { + console.error('Failed to fetch user session:', err); + } + }; + fetchUser(); + }, []); + + const handleSwitchChange = async (event: React.ChangeEvent) => { + const isChecked = event.target.checked; + + if (isChecked) { + setDialogMode('enable'); + setOpenPasswordDialog(true); + } else { + setDialogMode('disable'); + setOpenPasswordDialog(true); + } + }; + + const handleEnable2FA = async () => { + if (!password) { + setError('Password is required'); + return; + } + + setLoading(true); + setError(''); + + try { + const { data, error } = await authClient.twoFactor.enable({ + password, + }); + + if (error) { + setError(error.message || 'Failed to enable 2FA'); + return; + } + + if (data) { + const totpRes = await authClient.twoFactor.getTotpUri({ + password + }); + + if (totpRes.error) { + setError(totpRes.error.message || 'Failed to get QR code'); + return; + } + + if (totpRes.data?.totpURI) { + setTotpURI(totpRes.data.totpURI); + setOpenPasswordDialog(false); + setOpenQRDialog(true); + setPassword(''); + } + } + } catch (err: any) { + setError(err.message || 'An error occurred'); + } finally { + setLoading(false); + } + }; + + const handleVerifyTOTP = async () => { + if (!totpCode || totpCode.length !== 6) { + setError('Please enter a valid 6-digit code'); + return; + } + + setLoading(true); + setError(''); + + try { + const { error } = await authClient.twoFactor.verifyTotp({ + code: totpCode, + }); + + if (error) { + setError(error.message || 'Invalid TOTP code'); + return; + } + + // Successfully verified - show backup codes + setTwoFactorEnabled(true); + setOpenQRDialog(false); + setTotpCode(''); + } catch (err: any) { + setError(err.message || 'An error occurred'); + } finally { + setLoading(false); + } + }; + + const handleDisable2FA = async () => { + if (!password) { + setError('Password is required'); + return; + } + + setLoading(true); + setError(''); + + try { + const { error } = await authClient.twoFactor.disable({ + password, + }); + + if (error) { + setError(error.message || 'Failed to disable 2FA'); + setTwoFactorEnabled(true); + return; + } + + setTwoFactorEnabled(false); + setOpenPasswordDialog(false); + setPassword(''); + } catch (err: any) { + setError(err.message || 'An error occurred'); + setTwoFactorEnabled(true); + } finally { + setLoading(false); + } + }; + + const handleCloseDialog = () => { + setOpenPasswordDialog(false); + setPassword(''); + setError(''); + }; + + const handleCloseQRDialog = () => { + setOpenQRDialog(false); + setTotpCode(''); + setError(''); + setTotpURI(''); + }; + + const handleSubmit = () => { + if (dialogMode === 'enable') { + handleEnable2FA(); + } else { + handleDisable2FA(); + } + }; + + return ( + <> + + + + Manage 2FA Features + + + } + label="Enable Two-Factor Authentication (2FA)" + sx={{ gap: 2, ml: 0 }} + /> + + + + {/* Password Dialog */} + + + {dialogMode === 'enable' ? 'Enable' : 'Disable'} Two-Factor Authentication + + + + + Enter password + + setPassword(e.target.value)} + fullWidth + autoFocus + error={!!error} + helperText={error} + /> + + + + + + + + + {/* QR Code and Verification Dialog */} + + Scan QR Code + + + + Scan this QR code with your authenticator app (Google Authenticator, Authy, etc.) + + {totpURI ? ( + + + + ) : ( + + + + )} + + After scanning, enter the 6-digit code from your authenticator app: + + setTotpCode(e.target.value.replace(/\D/g, '').slice(0, 6))} + fullWidth + autoFocus + error={!!error} + helperText={error} + inputProps={{ maxLength: 6 }} + /> + + + + + + + + + ); +}; + +export default TwoFactorFeatures; diff --git a/apps/client/src/components/sections/authentications/default/LoginForm.tsx b/apps/client/src/components/sections/authentications/default/LoginForm.tsx index cd4a205..9597bcf 100644 --- a/apps/client/src/components/sections/authentications/default/LoginForm.tsx +++ b/apps/client/src/components/sections/authentications/default/LoginForm.tsx @@ -14,14 +14,21 @@ import { Stack, TextField, Typography, + Dialog, + DialogContent, } from '@mui/material'; +import dayjs from 'dayjs'; import * as yup from 'yup'; import { authClient } from '@/auth'; import Grid from '@mui/material/Grid'; import SocialAuth from './SocialAuth'; import { rootPaths } from 'routes/paths'; +import useCountdown from 'hooks/useCountdown'; +import IconifyIcon from 'components/base/IconifyIcon'; +import StyledTextField from 'components/styled/StyledTextField'; import PasswordTextField from 'components/common/PasswordTextField'; import DefaultCredentialAlert from '../common/DefaultCredentialAlert'; +import { useState, useEffect, useRef, ChangeEvent, Fragment } from 'react'; interface LoginFormProps { signUpLink: string; @@ -42,6 +49,8 @@ const schema = yup.object({ export type LoginFormValues = yup.InferType; +const totalInputLength = 6; + const LoginForm = ({ signUpLink, forgotPasswordLink, @@ -50,6 +59,18 @@ const LoginForm = ({ defaultCredential, }: LoginFormProps) => { const router = useRouter(); + const [passkeyError, setPasskeyError] = useState(""); + const [isSigningInWithPasskey, setIsSigningInWithPasskey] = useState(false); + const [passkeyAvailable, setPasskeyAvailable] = useState(false); + + const [show2FADialog, setShow2FADialog] = useState(false); + const [twoFactorError, setTwoFactorError] = useState(''); + const [isVerifying2FA, setIsVerifying2FA] = useState(false); + + const [otp, setOtp] = useState(''); + const inputRefs = useRef<(HTMLInputElement | null)[]>([]); + const [otpSent, setOtpSent] = useState(false); + const { time, startTimer } = useCountdown(); const searchParams = useSearchParams(); const callbackUrl = searchParams.get('callbackUrl'); @@ -66,177 +87,521 @@ const LoginForm = ({ }, }); + useEffect(() => { + const checkPasskeyAvailability = async () => { + if (window.PublicKeyCredential) { + const available = await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(); + setPasskeyAvailable(available); + + if (available) { + handlePasskeySignIn(true); + } + } + }; + + checkPasskeyAvailability(); + }, []); + const onSubmit = async (data: LoginFormValues) => { - const { data: loginData, error } = await authClient.signIn.email({ - email: data.email, - password: data.password, - rememberMe: data.rememberMe, - }); + const { data: loginData, error } = await authClient.signIn.email( + { + email: data.email, + password: data.password, + rememberMe: data.rememberMe, + }, + { + async onSuccess(context) { + if (context.data.twoFactorRedirect) { + setShow2FADialog(true); + sentOtp(); + } else { + router.push(callbackUrl ? callbackUrl : rootPaths.root); + } + }, + } + ); - if (loginData) { - router.push(callbackUrl ? callbackUrl : rootPaths.root); - } if (error) { setError('root.credential', { type: 'manual', message: error.message }); } }; + const handleVerify2FA = async () => { + if (!otp || otp.length !== totalInputLength) { + setTwoFactorError('Please enter a valid 6-digit code'); + return; + } + + setIsVerifying2FA(true); + setTwoFactorError(''); + + try { + const { data, error } = await authClient.twoFactor.verifyTotp({ + code: otp, + }); + + if (error) { + setTwoFactorError(error.message || 'Invalid verification code'); + inputRefs.current.forEach((input) => { + if (input) input.value = ''; + }); + setOtp(''); + inputRefs.current[0]?.focus(); + return; + } + + if (data) { + setShow2FADialog(false); + router.push(callbackUrl ? callbackUrl : rootPaths.root); + } + } catch (err: any) { + setTwoFactorError(err.message || 'An error occurred during verification'); + } finally { + setIsVerifying2FA(false); + } + }; + + const handleClose2FADialog = () => { + setShow2FADialog(false); + setOtp(''); + setTwoFactorError(''); + inputRefs.current.forEach((input) => { + if (input) input.value = ''; + }); + }; + + const handleChange = (e: ChangeEvent, index: number): void => { + const { value } = e.target; + if (value) { + [...value].slice(0, totalInputLength).forEach((char, charIndex) => { + if (inputRefs.current && inputRefs.current[index + charIndex]) { + inputRefs.current[index + charIndex]!.value = char; + inputRefs.current[index + charIndex + 1]?.focus(); + } + }); + const updatedOtp = inputRefs.current.reduce((acc, input) => acc + (input?.value || ''), ''); + setOtp(updatedOtp); + } + }; + + const handleKeydown = (event: React.KeyboardEvent, index: number) => { + if (event.key === 'Backspace') { + inputRefs.current[index]!.value = ''; + inputRefs.current[index - 1]?.focus(); + inputRefs.current[index - 1]?.select(); + + const updatedOtp = inputRefs.current.reduce((acc, input) => acc + (input?.value || ''), ''); + setOtp(updatedOtp); + } + if (event.key === 'ArrowLeft') { + inputRefs.current[index - 1]?.focus(); + inputRefs.current[index - 1]?.select(); + } + if (event.key === 'ArrowRight') { + inputRefs.current[index + 1]?.focus(); + inputRefs.current[index + 1]?.select(); + } + }; + + const sentOtp = () => { + setOtpSent(true); + startTimer(30, () => { + setOtpSent(false); + }); + }; + + useEffect(() => { + sentOtp(); + }, []); + + const handlePasskeySignIn = async (autoFill: boolean = false) => { + setIsSigningInWithPasskey(true); + setPasskeyError(""); + + try { + const { data, error } = await authClient.signIn.passkey({ + autoFill, + }); + + if (error) { + if (!autoFill) { + setPasskeyError(error.message || "Failed to sign in with passkey"); + } + } else if (data) { + router.push(callbackUrl ? callbackUrl : rootPaths.root); + } + } catch (err) { + if (!autoFill) { + setPasskeyError("An unexpected error occurred"); + } + } finally { + setIsSigningInWithPasskey(false); + } + }; + return ( - -
- - + - - - Log in - + + - Don't have an account? - - Sign up - - - - - {socialAuth && ( - <> - - - - - or use email - - - )} - - - - {errors.root?.credential?.message && ( - - {errors.root?.credential?.message} - - )} - {defaultCredential && } - - Log in + - {errors.email?.message}} - {...register('email')} - /> - - + Sign up + + + + + + {passkeyAvailable && ( + + + {passkeyError && ( + + {passkeyError} + + )} + + )} + + {passkeyAvailable && ( + + or + + )} + + {socialAuth && ( + <> + + - - + or use email + + + )} + + + + {errors.root?.credential?.message && ( + + {errors.root?.credential?.message} + + )} + {defaultCredential && } + + + {errors.email?.message}} + {...register('email')} + /> + + + {errors.password?.message}} + {...register('password')} + /> + + - {rememberDevice && ( - } - label={ - - Remember this device - - } - /> - )} - - {forgotPasswordLink && ( - - Forgot Password? - - )} - + + {rememberDevice && ( + } + label={ + + Remember this device + + } + /> + )} + + {forgotPasswordLink && ( + + Forgot Password? + + )} + + + + + + + + + {/* + Trouble signing in? + */} + + + {/* 2FA Verification Dialog */} + + + + - + Enter the OTP + + + A 6-digit one time password (OTP) has been sent to your authenticator app + + {twoFactorError && ( + + {twoFactorError} + + )} + + Didn't receive the code?{' '} + sentOtp()} + sx={{ + fontWeight: 'medium', + ml: 0.5, + }} + > + Send again {otpSent && <>in {dayjs(time * 1000).format('m:ss')} s} + + + + + + + + + {Array(totalInputLength) + .fill('') + .map((_, index) => ( + + + { + inputRefs.current[index] = el; + }} + type="number" + disabledSpinButton + sx={{ width: '42px', textAlign: 'center' }} + slotProps={{ + input: { + sx: { + '& .MuiInputBase-input': { + textAlign: 'center', + px: '12px !important', + }, + }, + }, + }} + onClick={() => inputRefs.current[index]?.select()} + onFocus={() => inputRefs.current[index]?.select()} + onKeyUp={(e) => handleKeydown(e, index)} + onChange={(e: ChangeEvent) => handleChange(e, index)} + size="large" + disabled={isVerifying2FA} + /> + + {index === totalInputLength / 2 - 1 && ( + - + )} + + ))} + + + + } + label={ + + Remember this device + + } + /> + + + + + + + + + - - - - - Trouble signing in? - - + + + + ); }; diff --git a/apps/client/src/components/sections/authentications/default/SignupForm.tsx b/apps/client/src/components/sections/authentications/default/SignupForm.tsx index 6a5a478..dbedf68 100644 --- a/apps/client/src/components/sections/authentications/default/SignupForm.tsx +++ b/apps/client/src/components/sections/authentications/default/SignupForm.tsx @@ -4,13 +4,28 @@ import { Alert, Box, Button, + Dialog, + DialogActions, + DialogContent, + DialogContentText, + DialogTitle, Divider, Link, + Radio, + RadioGroup, + FormControlLabel, + FormControl, + FormLabel, Stack, TextField, Typography, + Tabs, + Tab, + CircularProgress, } from "@mui/material"; import * as yup from "yup"; +import { useState } from "react"; +import QRCode from "react-qr-code"; import { authClient } from "@/auth"; import Grid from "@mui/material/Grid"; import SocialAuth from "./SocialAuth"; @@ -46,6 +61,16 @@ const SignupForm = ({ socialAuth, }: SignupFormProps) => { const router = useRouter(); + const [showSecurityDialog, setShowSecurityDialog] = useState(false); + const [passkeyName, setPasskeyName] = useState(""); + const [authenticatorType, setAuthenticatorType] = useState<"platform" | "cross-platform">("platform"); + const [passkeyError, setPasskeyError] = useState(""); + const [isAddingPasskey, setIsAddingPasskey] = useState(false); + const [activeTab, setActiveTab] = useState(0); + const [totpCode, setTotpCode] = useState(''); + const [totpURI, setTotpURI] = useState(''); + const [qrError, setQrError] = useState(''); + const [isSettingUp2FA, setIsSettingUp2FA] = useState(false); const { register, @@ -64,164 +89,391 @@ const SignupForm = ({ }); if (signupData) { - router.push(rootPaths.root); + setShowSecurityDialog(true); + await fetch2FAuth(data.password); } if (error) { setError('root.credential', { type: 'manual', message: error.message }); } }; + const fetch2FAuth = async (password: string) => { + try { + const { data, error } = await authClient.twoFactor.enable({ + password, + }); + + if (!error && data) { + const totpRes = await authClient.twoFactor.getTotpUri({ + password + }); + + if (totpRes.data?.totpURI) { + setTotpURI(totpRes.data.totpURI); + } + } + } catch (err) { + console.error('Failed to fetch 2FA URI:', err); + } + }; + + const handleVerifyTOTP = async () => { + if (!totpCode || totpCode.length !== 6) { + setQrError('Please enter a valid 6-digit code'); + return; + } + + setIsSettingUp2FA(true); + setQrError(''); + + try { + const { error } = await authClient.twoFactor.verifyTotp({ + code: totpCode, + }); + + if (error) { + setQrError(error.message || 'Invalid TOTP code'); + return; + } + + setShowSecurityDialog(false); + router.push(rootPaths.root); + } catch (err: any) { + setQrError(err.message || 'An error occurred'); + } finally { + setIsSettingUp2FA(false); + } + }; + + const handleAddPasskey = async () => { + setIsAddingPasskey(true); + setPasskeyError(""); + + try { + const response = await authClient.passkey.addPasskey({ + name: passkeyName || "My Device", + authenticatorAttachment: authenticatorType, + }); + + if (response?.error) { + setPasskeyError(response.error.message || "Failed to add passkey"); + } else if (response?.data) { + router.push(rootPaths.root); + } else { + router.push(rootPaths.root); + } + } catch (err) { + setPasskeyError("An unexpected error occurred"); + } finally { + setIsAddingPasskey(false); + } + }; + + const handleSkipPasskey = () => { + setShowSecurityDialog(false); + router.push(rootPaths.root); + }; + return ( - -
- - + - - - Sign up - + + + + - Already have an account? - - Log in - - - - - {socialAuth && ( - <> - - - - - or use email - - - )} - - - {errors.root?.credential?.message && ( - - {errors.root?.credential?.message} - - )} - - - {errors.name?.message}} - {...register("name")} - /> - - Sign up + - {errors.email?.message}} - {...register("email")} - /> - - - {errors.password?.message}} - {...register("password")} - /> - - - - {" "} - This site is protected by reCAPTCHA and the Google Privacy - Policy and Terms of Service apply. By clicking the Create - Account button, you are agreeing to the{" "} - terms and conditions. - + color: "text.secondary", + }}> + Already have an account? + + Log in + + + + + {socialAuth && ( + <> + + - + or use email + + + )} + + + {errors.root?.credential?.message && ( + + {errors.root?.credential?.message} + + )} + + + {errors.name?.message}} + {...register("name")} + /> + + + {errors.email?.message}} + {...register("email")} + /> + + + {errors.password?.message}} + {...register("password")} + /> + + + + {" "} + This site is protected by reCAPTCHA and the Google Privacy + Policy and Terms of Service apply. By clicking the Create + Account button, you are agreeing to the{" "} + terms and conditions. + + + + + - - + + - - - Trouble signing in? - - + {/* + Trouble signing in? + */} + + + + + setActiveTab(newValue)}> + } + iconPosition="start" + label="Set Up Passkey" + /> + } + iconPosition="start" + label="Set QR Code" + /> + + + + {activeTab === 0 && ( + <> + + Enhance your account security with a passkey. Use your fingerprint, face, or device PIN for quick and secure access. + + + {passkeyError && ( + + {passkeyError} + + )} + + setPasskeyName(e.target.value)} + sx={{ mb: 3 }} + variant="outlined" + /> + + + + Authentication Method + + setAuthenticatorType(e.target.value as "platform" | "cross-platform")} + > + } + label={ + + + + This Device + + + (Use biometrics or PIN on this device) + + + } + /> + } + label={ + + + + Security Key + + + (Use a USB security key or another device) + + + } + /> + + + + )} + + {activeTab === 1 && ( + + + Scan this QR code with your authenticator app (Google Authenticator, Authy, etc.) + + {totpURI ? ( + + + + ) : ( + + + + )} + + After scanning, enter the 6-digit code from your authenticator app: + + + {qrError && ( + + {qrError} + + )} + + setTotpCode(e.target.value.replace(/\D/g, '').slice(0, 6))} + fullWidth + autoFocus + error={!!qrError} + inputProps={{ maxLength: 6 }} + /> + + )} + + + + {activeTab === 0 ? ( + + ) : ( + + )} + + + ); }; diff --git a/apps/client/src/data/account/account-tabs.tsx b/apps/client/src/data/account/account-tabs.tsx new file mode 100644 index 0000000..b3ca18c --- /dev/null +++ b/apps/client/src/data/account/account-tabs.tsx @@ -0,0 +1,24 @@ +import { AccountTab } from 'types/accounts'; +import PersonalInfoTabPanel from 'components/sections/account/personal-info/PersonalInfoTabPanel'; +import TouchIDTabPanel from 'components/sections/account/touch-id/TouchIdTabPanel'; + +export const accountTabs: AccountTab[] = [ + { + id: 1, + label: 'Personal Information', + title: 'Personal Info', + value: 'personal_information', + icon: 'material-symbols:person-outline', + panelIcon: 'material-symbols:person-outline', + tabPanel: , + }, + { + id: 12, + label: 'Configure MFA', + title: 'Configure MFA', + value: 'touch_id', + icon: 'material-symbols:touch-app-outline', + panelIcon: 'material-symbols:touch-app-outline', + tabPanel: , + }, +]; diff --git a/apps/client/src/data/account/personal-info.ts b/apps/client/src/data/account/personal-info.ts new file mode 100644 index 0000000..47e85c6 --- /dev/null +++ b/apps/client/src/data/account/personal-info.ts @@ -0,0 +1,16 @@ +import { PersonalInfo } from 'types/accounts'; + +export const personalInfoData: PersonalInfo = { + firstName: 'Luke', + lastName: 'Skywalker', + userName: 'LukeSkywalker212', + birthDate: '2004-06-03', + country: 'United States', + state: 'Pennsylvania', + city: 'Essington', + street: '500 Powhattan Ave', + zip: '19029', + phoneNumber: '(+880)1795448106', + primaryEmail: 'something@email.com', + secondaryEmail: 'something.alternate@email.com', +}; diff --git a/apps/client/src/data/account/shipping-billing-address.ts b/apps/client/src/data/account/shipping-billing-address.ts new file mode 100644 index 0000000..a988702 --- /dev/null +++ b/apps/client/src/data/account/shipping-billing-address.ts @@ -0,0 +1,25 @@ +import { AddressInfo } from 'types/accounts'; + +export const shippingAddressData: AddressInfo = { + name: 'Tsamina Mina', + phoneNumber: '+8801234567890', + emailAddress: 'tsaminamina@gmail.com', + country: 'United States', + state: 'Pennsylvania', + city: 'Essington', + street: '500 Powhattan Ave', + zip: '19029', + addressType: 'Office', +}; + +export const billingAddressData: AddressInfo = { + name: 'Megumi Fushigoro', + phoneNumber: '+8800987654321', + emailAddress: 'megumifushigoro@gmail.com', + country: 'United Kingdom', + state: 'London', + city: 'Birmingham', + street: '200 Street', + zip: '12222', + addressType: 'Office', +}; diff --git a/apps/client/src/data/account/storage.ts b/apps/client/src/data/account/storage.ts new file mode 100644 index 0000000..29105f3 --- /dev/null +++ b/apps/client/src/data/account/storage.ts @@ -0,0 +1,62 @@ +import { Storage, BackupSyncSettings } from 'types/accounts'; + +export const backupSyncSettings: BackupSyncSettings[] = [ + { name: 'Photos', enabled: true }, + { name: 'Email', enabled: false }, + { name: 'Contacts', enabled: true }, + { name: 'Videos', enabled: true }, + { name: 'Chats', enabled: true }, + { name: 'Calendar', enabled: false }, + { name: 'Notes', enabled: false }, + { name: 'Passwords', enabled: true }, + { name: 'Map', enabled: false }, +]; + +export const storageData: Storage = { + totalSpaceinKb: 20971520, + totalSpaceUsedinKb: 19115540.48, + categories: [ + { + name: 'Photos', + icon: 'material-symbols:imagesmode-outline', + color: 'info.main', + fileCount: 580, + spaceUsedinKb: 6920601.6, + }, + { + name: 'Videos', + icon: 'material-symbols:video-file-outline-rounded', + color: 'primary.main', + fileCount: 32, + spaceUsedinKb: 3355443.2, + }, + { + name: 'Documents', + icon: 'material-symbols:description-outline-rounded', + color: 'warning.main', + fileCount: 580, + spaceUsedinKb: 3879731.2, + }, + { + name: 'Email', + icon: 'material-symbols:mail-outline-rounded', + color: 'success.main', + fileCount: 356, + spaceUsedinKb: 1887436.8, + }, + { + name: 'Chats', + icon: 'material-symbols:chat-outline-rounded', + color: 'error.main', + fileCount: 39, + spaceUsedinKb: 524288, + }, + { + name: 'Others', + icon: 'material-symbols:article-outline-rounded', + color: 'grey.500', + fileCount: 948, + spaceUsedinKb: 2202009.6, + }, + ], +}; diff --git a/apps/client/src/data/account/user-permissions.tsx b/apps/client/src/data/account/user-permissions.tsx new file mode 100644 index 0000000..37aa96d --- /dev/null +++ b/apps/client/src/data/account/user-permissions.tsx @@ -0,0 +1,46 @@ +import { Stack, Typography } from '@mui/material'; +import { Permission } from 'types/accounts'; + +export const globalPermissions: Permission[] = [ + { + name: 'administrator', + checked: false, + label: ( + + + Administrator + + + Has full access but can't transfer ownership + + + ), + }, + { + name: 'billing', + checked: false, + label: ( + + + Billing + + + Users can modify plans, but domains and Google Workspace are excluded. + + + ), + }, +]; + +export const userPermissions: Permission[] = [ + { + name: 'deleteAccount', + checked: false, + label: 'Permit Users to Delete Their Accounts', + }, + { + name: 'createOrganizatio', + checked: true, + label: 'Enable Users to Create Organizations', + }, +]; diff --git a/apps/client/src/data/account/work-education-history.ts b/apps/client/src/data/account/work-education-history.ts new file mode 100644 index 0000000..5dde515 --- /dev/null +++ b/apps/client/src/data/account/work-education-history.ts @@ -0,0 +1,59 @@ +import harvardLogo from 'assets/images/logo/harvard_logo.webp'; +import mailblusterLogo from 'assets/images/logo/mailbluster_logo.webp'; +import ndcLogo from 'assets/images/logo/ndc_logo.webp'; +import technextLogo from 'assets/images/logo/technext_logo.webp'; +import themewagonLogo from 'assets/images/logo/themewagon_logo.webp'; +import { EducationHistory, WorkHistory } from 'types/accounts'; + +export const workHistory: WorkHistory[] = [ + { + id: 1, + companyName: 'ThemeWagon Inc.', + companyLogo: themewagonLogo, + designation: 'UX/UI Designer', + location: 'Dhaka, Bangladesh', + startDate: '2023-12-01', + currentlyWorking: true, + }, + { + id: 2, + companyName: 'MailBluster Inc.', + companyLogo: mailblusterLogo, + designation: 'Jr. UX/UI Designer', + location: 'Dhaka, Bangladesh', + startDate: '2022-04-01', + endDate: '2023-11-01', + currentlyWorking: false, + }, + { + id: 3, + companyName: 'TechNext Ltd.', + companyLogo: technextLogo, + designation: 'Intern', + location: 'Dhaka, Bangladesh', + startDate: '2021-04-01', + endDate: '2022-03-01', + currentlyWorking: false, + }, +]; + +export const educationHistory: EducationHistory[] = [ + { + id: 1, + institutionName: 'Harvard University', + institutionLogo: harvardLogo, + subject: 'Human Interaction Design', + location: 'Sylhet, Bangladesh', + startDate: '2014-01-01', + endDate: '2019-12-01', + }, + { + id: 2, + institutionName: 'Notre Dame College', + institutionLogo: ndcLogo, + subject: '', + location: 'Dhaka, Bangladesh', + startDate: '2012-01-01', + endDate: '2013-12-01', + }, +]; diff --git a/apps/client/src/data/countries.ts b/apps/client/src/data/countries.ts new file mode 100644 index 0000000..993a915 --- /dev/null +++ b/apps/client/src/data/countries.ts @@ -0,0 +1,634 @@ +import { Country } from 'types/countries'; + +export const countries: Country[] = [ + { code: 'AD', label: 'Andorra', phone: '376', flag: 'flag:ad-4x3' }, + { + code: 'AE', + label: 'United Arab Emirates', + phone: '971', + flag: 'flag:ae-4x3', + }, + { + code: 'AF', + label: 'Afghanistan', + phone: '93', + flag: 'flag:af-4x3', + }, + { + code: 'AG', + label: 'Antigua and Barbuda', + phone: '268', + flag: 'flag:ag-4x3', + }, + { code: 'AI', label: 'Anguilla', phone: '264', flag: 'flag:ai-4x3' }, + { code: 'AL', label: 'Albania', phone: '355', flag: 'flag:al-4x3' }, + { code: 'AM', label: 'Armenia', phone: '374', flag: 'flag:am-4x3' }, + { code: 'AO', label: 'Angola', phone: '244', flag: 'flag:ao-4x3' }, + { + code: 'AQ', + label: 'Antarctica', + phone: '672', + flag: 'flag:aq-4x3', + }, + { code: 'AR', label: 'Argentina', phone: '54', flag: 'flag:ar-4x3' }, + { + code: 'AS', + label: 'American Samoa', + phone: '684', + flag: 'flag:as-4x3', + }, + { code: 'AT', label: 'Austria', phone: '43', flag: 'flag:at-4x3' }, + { code: 'AU', label: 'Australia', phone: '61', flag: 'flag:au-4x3' }, + { code: 'AW', label: 'Aruba', phone: '297', flag: 'flag:aw-4x3' }, + { + code: 'AX', + label: 'Alland Islands', + phone: '358', + flag: 'flag:ax-4x3', + }, + { + code: 'AZ', + label: 'Azerbaijan', + phone: '994', + flag: 'flag:az-4x3', + }, + { + code: 'BA', + label: 'Bosnia and Herzegovina', + phone: '387', + flag: 'flag:ba-4x3', + }, + { code: 'BB', label: 'Barbados', phone: '246', flag: 'flag:bb-4x3' }, + { + code: 'BD', + label: 'Bangladesh', + phone: '880', + flag: 'flag:bd-4x3', + }, + { code: 'BE', label: 'Belgium', phone: '32', flag: 'flag:be-4x3' }, + { + code: 'BF', + label: 'Burkina Faso', + phone: '226', + flag: 'flag:bf-4x3', + }, + { code: 'BG', label: 'Bulgaria', phone: '359', flag: 'flag:bg-4x3' }, + { code: 'BH', label: 'Bahrain', phone: '973', flag: 'flag:bh-4x3' }, + { code: 'BI', label: 'Burundi', phone: '257', flag: 'flag:bi-4x3' }, + { code: 'BJ', label: 'Benin', phone: '229', flag: 'flag:bj-4x3' }, + { + code: 'BL', + label: 'Saint Barthelemy', + phone: '590', + flag: 'flag:bl-4x3', + }, + { code: 'BM', label: 'Bermuda', phone: '441', flag: 'flag:bm-4x3' }, + { + code: 'BN', + label: 'Brunei Darussalam', + phone: '673', + flag: 'flag:bn-4x3', + }, + { code: 'BO', label: 'Bolivia', phone: '591', flag: 'flag:bo-4x3' }, + { code: 'BR', label: 'Brazil', phone: '55', flag: 'flag:br-4x3' }, + { code: 'BS', label: 'Bahamas', phone: '242', flag: 'flag:bs-4x3' }, + { code: 'BT', label: 'Bhutan', phone: '975', flag: 'flag:bt-4x3' }, + { + code: 'BV', + label: 'Bouvet Island', + phone: '47', + flag: 'flag:bv-4x3', + }, + { code: 'BW', label: 'Botswana', phone: '267', flag: 'flag:bw-4x3' }, + { code: 'BY', label: 'Belarus', phone: '375', flag: 'flag:by-4x3' }, + { code: 'BZ', label: 'Belize', phone: '501', flag: 'flag:bz-4x3' }, + { code: 'CA', label: 'Canada', phone: '1', flag: 'flag:ca-4x3' }, + { + code: 'CD', + label: 'Congo, Democratic Republic of the', + phone: '243', + flag: 'flag:cd-4x3', + }, + { + code: 'CF', + label: 'Central African Republic', + phone: '236', + flag: 'flag:cf-4x3', + }, + { + code: 'CH', + label: 'Switzerland', + phone: '41', + flag: 'flag:ch-4x3', + }, + { + code: 'CI', + label: "Cote d'Ivoire", + phone: '225', + flag: 'flag:ci-4x3', + }, + { + code: 'CK', + label: 'Cook Islands', + phone: '682', + flag: 'flag:ck-4x3', + }, + { code: 'CL', label: 'Chile', phone: '56', flag: 'flag:cl-4x3' }, + { code: 'CM', label: 'Cameroon', phone: '237', flag: 'flag:cm-4x3' }, + { code: 'CN', label: 'China', phone: '86', flag: 'flag:cn-4x3' }, + { code: 'CO', label: 'Colombia', phone: '57', flag: 'flag:co-4x3' }, + { + code: 'CR', + label: 'Costa Rica', + phone: '506', + flag: 'flag:cr-4x3', + }, + { code: 'CU', label: 'Cuba', phone: '53', flag: 'flag:cu-4x3' }, + { + code: 'CV', + label: 'Cape Verde', + phone: '238', + flag: 'flag:cv-4x3', + }, + { code: 'CW', label: 'Curacao', phone: '599', flag: 'flag:cw-4x3' }, + { code: 'CY', label: 'Cyprus', phone: '357', flag: 'flag:cy-4x3' }, + { + code: 'CZ', + label: 'Czech Republic', + phone: '420', + flag: 'flag:cz-4x3', + }, + { code: 'DE', label: 'Germany', phone: '49', flag: 'flag:de-4x3' }, + { code: 'DJ', label: 'Djibouti', phone: '253', flag: 'flag:dj-4x3' }, + { code: 'DK', label: 'Denmark', phone: '45', flag: 'flag:dk-4x3' }, + { code: 'DM', label: 'Dominica', phone: '767', flag: 'flag:dm-4x3' }, + { + code: 'DO', + label: 'Dominican Republic', + phone: '809', + flag: 'flag:do-4x3', + }, + { code: 'DZ', label: 'Algeria', phone: '213', flag: 'flag:dz-4x3' }, + { code: 'EC', label: 'Ecuador', phone: '593', flag: 'flag:ec-4x3' }, + { code: 'EE', label: 'Estonia', phone: '372', flag: 'flag:ee-4x3' }, + { code: 'EG', label: 'Egypt', phone: '20', flag: 'flag:eg-4x3' }, + { + code: 'EH', + label: 'Western Sahara', + phone: '212', + flag: 'flag:eh-4x3', + }, + { code: 'ER', label: 'Eritrea', phone: '291', flag: 'flag:er-4x3' }, + { code: 'ES', label: 'Spain', phone: '34', flag: 'flag:es-4x3' }, + { code: 'ET', label: 'Ethiopia', phone: '251', flag: 'flag:et-4x3' }, + { code: 'FJ', label: 'Fiji', phone: '679', flag: 'flag:fj-4x3' }, + { + code: 'FK', + label: 'Falkland Islands (Malvinas)', + phone: '500', + flag: 'flag:fk-4x3', + }, + { + code: 'FM', + label: 'Micronesia, Federated States of', + phone: '691', + flag: 'flag:fm-4x3', + }, + { + code: 'FO', + label: 'Faroe Islands', + phone: '298', + flag: 'flag:fo-4x3', + }, + { code: 'FR', label: 'France', phone: '33', flag: 'flag:fr-4x3' }, + { code: 'GA', label: 'Gabon', phone: '241', flag: 'flag:ga-4x3' }, + { + code: 'GB', + label: 'United Kingdom', + phone: '44', + flag: 'flag:gb-4x3', + }, + { code: 'GD', label: 'Grenada', phone: '473', flag: 'flag:gd-4x3' }, + { code: 'GE', label: 'Georgia', phone: '995', flag: 'flag:ge-4x3' }, + { + code: 'GF', + label: 'French Guiana', + phone: '594', + flag: 'flag:gf-4x3', + }, + { code: 'GH', label: 'Ghana', phone: '233', flag: 'flag:gh-4x3' }, + { code: 'GI', label: 'Gibraltar', phone: '350', flag: 'flag:gi-4x3' }, + { code: 'GL', label: 'Greenland', phone: '299', flag: 'flag:gl-4x3' }, + { code: 'GM', label: 'Gambia', phone: '220', flag: 'flag:gm-4x3' }, + { code: 'GN', label: 'Guinea', phone: '224', flag: 'flag:gn-4x3' }, + { + code: 'GQ', + label: 'Equatorial Guinea', + phone: '240', + flag: 'flag:gq-4x3', + }, + { code: 'GR', label: 'Greece', phone: '30', flag: 'flag:gr-4x3' }, + { code: 'GT', label: 'Guatemala', phone: '502', flag: 'flag:gt-4x3' }, + { code: 'GU', label: 'Guam', phone: '671', flag: 'flag:gu-4x3' }, + { + code: 'GW', + label: 'Guinea-Bissau', + phone: '245', + flag: 'flag:gw-4x3', + }, + { code: 'GY', label: 'Guyana', phone: '592', flag: 'flag:gy-4x3' }, + { code: 'HK', label: 'Hong Kong', phone: '852', flag: 'flag:hk-4x3' }, + { code: 'HN', label: 'Honduras', phone: '504', flag: 'flag:hn-4x3' }, + { code: 'HR', label: 'Croatia', phone: '385', flag: 'flag:hr-4x3' }, + { code: 'HT', label: 'Haiti', phone: '509', flag: 'flag:ht-4x3' }, + { code: 'HU', label: 'Hungary', phone: '36', flag: 'flag:hu-4x3' }, + { code: 'ID', label: 'Indonesia', phone: '62', flag: 'flag:id-4x3' }, + { code: 'IE', label: 'Ireland', phone: '353', flag: 'flag:ie-4x3' }, + { code: 'IL', label: 'Israel', phone: '972', flag: 'flag:il-4x3' }, + { code: 'IN', label: 'India', phone: '91', flag: 'flag:in-4x3' }, + { code: 'IQ', label: 'Iraq', phone: '964', flag: 'flag:iq-4x3' }, + { + code: 'IR', + label: 'Iran, Islamic Republic of', + phone: '98', + flag: 'flag:ir-4x3', + }, + { code: 'IS', label: 'Iceland', phone: '354', flag: 'flag:is-4x3' }, + { code: 'IT', label: 'Italy', phone: '39', flag: 'flag:it-4x3' }, + { code: 'JM', label: 'Jamaica', phone: '876', flag: 'flag:jm-4x3' }, + { code: 'JO', label: 'Jordan', phone: '962', flag: 'flag:jo-4x3' }, + { code: 'JP', label: 'Japan', phone: '81', flag: 'flag:jp-4x3' }, + { code: 'KE', label: 'Kenya', phone: '254', flag: 'flag:ke-4x3' }, + { + code: 'KG', + label: 'Kyrgyzstan', + phone: '996', + flag: 'flag:kg-4x3', + }, + { code: 'KH', label: 'Cambodia', phone: '855', flag: 'flag:kh-4x3' }, + { code: 'KI', label: 'Kiribati', phone: '686', flag: 'flag:ki-4x3' }, + { code: 'KM', label: 'Comoros', phone: '269', flag: 'flag:km-4x3' }, + { + code: 'KN', + label: 'Saint Kitts and Nevis', + phone: '869', + flag: 'flag:kn-4x3', + }, + { + code: 'KP', + label: "Korea, Democratic People's Republic of", + phone: '850', + flag: 'flag:kp-4x3', + }, + { + code: 'KR', + label: 'Korea, Republic of', + phone: '82', + flag: 'flag:kr-4x3', + }, + { code: 'KW', label: 'Kuwait', phone: '965', flag: 'flag:kw-4x3' }, + { + code: 'KY', + label: 'Cayman Islands', + phone: '345', + flag: 'flag:ky-4x3', + }, + { code: 'KZ', label: 'Kazakhstan', phone: '7', flag: 'flag:kz-4x3' }, + { + code: 'LA', + label: "Lao People's Democratic Republic", + phone: '856', + flag: 'flag:la-4x3', + }, + { code: 'LB', label: 'Lebanon', phone: '961', flag: 'flag:lb-4x3' }, + { + code: 'LC', + label: 'Saint Lucia', + phone: '758', + flag: 'flag:lc-4x3', + }, + { + code: 'LI', + label: 'Liechtenstein', + phone: '423', + flag: 'flag:li-4x3', + }, + { code: 'LK', label: 'Sri Lanka', phone: '94', flag: 'flag:lk-4x3' }, + { code: 'LR', label: 'Liberia', phone: '231', flag: 'flag:lr-4x3' }, + { code: 'LS', label: 'Lesotho', phone: '266', flag: 'flag:ls-4x3' }, + { code: 'LT', label: 'Lithuania', phone: '370', flag: 'flag:lt-4x3' }, + { + code: 'LU', + label: 'Luxembourg', + phone: '352', + flag: 'flag:lu-4x3', + }, + { code: 'LV', label: 'Latvia', phone: '371', flag: 'flag:lv-4x3' }, + { code: 'LY', label: 'Libya', phone: '218', flag: 'flag:ly-4x3' }, + { code: 'MC', label: 'Monaco', phone: '377', flag: 'flag:mc-4x3' }, + { + code: 'MD', + label: 'Moldova, Republic of', + phone: '373', + flag: 'flag:md-4x3', + }, + { + code: 'ME', + label: 'Montenegro', + phone: '382', + flag: 'flag:me-4x3', + }, + { + code: 'MG', + label: 'Madagascar', + phone: '261', + flag: 'flag:mg-4x3', + }, + { + code: 'MH', + label: 'Marshall Islands', + phone: '692', + flag: 'flag:mh-4x3', + }, + { + code: 'MK', + label: 'Macedonia, the Former Yugoslav Republic of', + phone: '389', + flag: 'flag:mk-4x3', + }, + { code: 'ML', label: 'Mali', phone: '223', flag: 'flag:ml-4x3' }, + { code: 'MM', label: 'Myanmar', phone: '95', flag: 'flag:mm-4x3' }, + { code: 'MN', label: 'Mongolia', phone: '976', flag: 'flag:mn-4x3' }, + { code: 'MO', label: 'Macao', phone: '853', flag: 'flag:mo-4x3' }, + { + code: 'MP', + label: 'Northern Mariana Islands', + phone: '670', + flag: 'flag:mp-4x3', + }, + { + code: 'MQ', + label: 'Martinique', + phone: '596', + flag: 'flag:mq-4x3', + }, + { + code: 'MR', + label: 'Mauritania', + phone: '222', + flag: 'flag:mr-4x3', + }, + { + code: 'MS', + label: 'Montserrat', + phone: '664', + flag: 'flag:ms-4x3', + }, + { code: 'MT', label: 'Malta', phone: '356', flag: 'flag:mt-4x3' }, + { code: 'MU', label: 'Mauritius', phone: '230', flag: 'flag:mu-4x3' }, + { code: 'MV', label: 'Maldives', phone: '960', flag: 'flag:mv-4x3' }, + { code: 'MW', label: 'Malawi', phone: '265', flag: 'flag:mw-4x3' }, + { code: 'MX', label: 'Mexico', phone: '52', flag: 'flag:mx-4x3' }, + { code: 'MY', label: 'Malaysia', phone: '60', flag: 'flag:my-4x3' }, + { + code: 'MZ', + label: 'Mozambique', + phone: '258', + flag: 'flag:mz-4x3', + }, + { + code: 'NC', + label: 'New Caledonia', + phone: '687', + flag: 'flag:nc-4x3', + }, + { code: 'NE', label: 'Niger', phone: '227', flag: 'flag:ne-4x3' }, + { code: 'NG', label: 'Nigeria', phone: '234', flag: 'flag:ng-4x3' }, + { code: 'NI', label: 'Nicaragua', phone: '505', flag: 'flag:ni-4x3' }, + { + code: 'NL', + label: 'Netherlands', + phone: '31', + flag: 'flag:nl-4x3', + }, + { code: 'NP', label: 'Nepal', phone: '977', flag: 'flag:np-4x3' }, + { code: 'NR', label: 'Nauru', phone: '674', flag: 'flag:nr-4x3' }, + { code: 'NU', label: 'Niue', phone: '683', flag: 'flag:nu-4x3' }, + { + code: 'NZ', + label: 'New Zealand', + phone: '64', + flag: 'flag:nz-4x3', + }, + { code: 'OM', label: 'Oman', phone: '968', flag: 'flag:om-4x3' }, + { code: 'PA', label: 'Panama', phone: '507', flag: 'flag:pa-4x3' }, + { code: 'PE', label: 'Peru', phone: '51', flag: 'flag:pe-4x3' }, + { + code: 'PF', + label: 'French Polynesia', + phone: '689', + flag: 'flag:pf-4x3', + }, + { + code: 'PG', + label: 'Papua New Guinea', + phone: '675', + flag: 'flag:pg-4x3', + }, + { + code: 'PH', + label: 'Philippines', + phone: '63', + flag: 'flag:ph-4x3', + }, + { code: 'PK', label: 'Pakistan', phone: '92', flag: 'flag:pk-4x3' }, + { code: 'PL', label: 'Poland', phone: '48', flag: 'flag:pl-4x3' }, + { + code: 'PM', + label: 'Saint Pierre and Miquelon', + phone: '508', + flag: 'flag:pm-4x3', + }, + { code: 'PN', label: 'Pitcairn', phone: '870', flag: 'flag:pn-4x3' }, + { + code: 'PS', + label: 'Palestine, State of', + phone: '970', + flag: 'flag:ps-4x3', + }, + { code: 'PT', label: 'Portugal', phone: '351', flag: 'flag:pt-4x3' }, + { code: 'PW', label: 'Palau', phone: '680', flag: 'flag:pw-4x3' }, + { code: 'PY', label: 'Paraguay', phone: '595', flag: 'flag:py-4x3' }, + { code: 'QA', label: 'Qatar', phone: '974', flag: 'flag:qa-4x3' }, + { code: 'RE', label: 'Reunion', phone: '262', flag: 'flag:re-4x3' }, + { code: 'RO', label: 'Romania', phone: '40', flag: 'flag:ro-4x3' }, + { code: 'RS', label: 'Serbia', phone: '381', flag: 'flag:rs-4x3' }, + { code: 'RW', label: 'Rwanda', phone: '250', flag: 'flag:rw-4x3' }, + { + code: 'SA', + label: 'Saudi Arabia', + phone: '966', + flag: 'flag:sa-4x3', + }, + { + code: 'SB', + label: 'Solomon Islands', + phone: '677', + flag: 'flag:sb-4x3', + }, + { + code: 'SC', + label: 'Seychelles', + phone: '248', + flag: 'flag:sc-4x3', + }, + { code: 'SD', label: 'Sudan', phone: '249', flag: 'flag:sd-4x3' }, + { code: 'SE', label: 'Sweden', phone: '46', flag: 'flag:se-4x3' }, + { code: 'SG', label: 'Singapore', phone: '65', flag: 'flag:sg-4x3' }, + { + code: 'SH', + label: 'Saint Helena', + phone: '290', + flag: 'flag:sh-4x3', + }, + { code: 'SI', label: 'Slovenia', phone: '386', flag: 'flag:si-4x3' }, + { code: 'SK', label: 'Slovakia', phone: '421', flag: 'flag:sk-4x3' }, + { + code: 'SL', + label: 'Sierra Leone', + phone: '232', + flag: 'flag:sl-4x3', + }, + { + code: 'SM', + label: 'San Marino', + phone: '378', + flag: 'flag:sm-4x3', + }, + { code: 'SN', label: 'Senegal', phone: '221', flag: 'flag:sn-4x3' }, + { code: 'SO', label: 'Somalia', phone: '252', flag: 'flag:so-4x3' }, + { code: 'SR', label: 'Suriname', phone: '597', flag: 'flag:sr-4x3' }, + { + code: 'SS', + label: 'South Sudan', + phone: '211', + flag: 'flag:ss-4x3', + }, + { + code: 'ST', + label: 'Sao Tome and Principe', + phone: '239', + flag: 'flag:st-4x3', + }, + { + code: 'SV', + label: 'El Salvador', + phone: '503', + flag: 'flag:sv-4x3', + }, + { + code: 'SX', + label: 'Sint Maarten (Dutch part)', + phone: '721', + flag: 'flag:sx-4x3', + }, + { + code: 'SY', + label: 'Syrian Arab Republic', + phone: '963', + flag: 'flag:sy-4x3', + }, + { + code: 'TC', + label: 'Turks and Caicos Islands', + phone: '649', + flag: 'flag:tc-4x3', + }, + { code: 'TD', label: 'Chad', phone: '235', flag: 'flag:td-4x3' }, + { code: 'TG', label: 'Togo', phone: '228', flag: 'flag:tg-4x3' }, + { code: 'TH', label: 'Thailand', phone: '66', flag: 'flag:th-4x3' }, + { + code: 'TJ', + label: 'Tajikistan', + phone: '992', + flag: 'flag:tj-4x3', + }, + { code: 'TK', label: 'Tokelau', phone: '690', flag: 'flag:tk-4x3' }, + { + code: 'TM', + label: 'Turkmenistan', + phone: '993', + flag: 'flag:tm-4x3', + }, + { code: 'TN', label: 'Tunisia', phone: '216', flag: 'flag:tn-4x3' }, + { code: 'TO', label: 'Tonga', phone: '676', flag: 'flag:to-4x3' }, + { code: 'TR', label: 'Turkey', phone: '90', flag: 'flag:tr-4x3' }, + { + code: 'TT', + label: 'Trinidad and Tobago', + phone: '868', + flag: 'flag:tt-4x3', + }, + { code: 'TV', label: 'Tuvalu', phone: '688', flag: 'flag:tv-4x3' }, + { code: 'TW', label: 'Taiwan', phone: '886', flag: 'flag:tw-4x3' }, + { + code: 'TZ', + label: 'United Republic of Tanzania', + phone: '255', + flag: 'flag:tz-4x3', + }, + { code: 'UA', label: 'Ukraine', phone: '380', flag: 'flag:ua-4x3' }, + { code: 'UG', label: 'Uganda', phone: '256', flag: 'flag:ug-4x3' }, + { code: 'US', label: 'United States', phone: '1', flag: 'flag:us-4x3' }, + { code: 'UY', label: 'Uruguay', phone: '598', flag: 'flag:uy-4x3' }, + { + code: 'UZ', + label: 'Uzbekistan', + phone: '998', + flag: 'flag:uz-4x3', + }, + { + code: 'VA', + label: 'Holy See (Vatican City State)', + phone: '379', + flag: 'flag:va-4x3', + }, + { + code: 'VC', + label: 'Saint Vincent and the Grenadines', + phone: '784', + flag: 'flag:vc-4x3', + }, + { code: 'VE', label: 'Venezuela', phone: '58', flag: 'flag:ve-4x3' }, + { + code: 'VG', + label: 'British Virgin Islands', + phone: '284', + flag: 'flag:vg-4x3', + }, + { + code: 'VI', + label: 'US Virgin Islands', + phone: '340', + flag: 'flag:vi-4x3', + }, + { code: 'VN', label: 'Vietnam', phone: '84', flag: 'flag:vn-4x3' }, + { code: 'VU', label: 'Vanuatu', phone: '678', flag: 'flag:vu-4x3' }, + { + code: 'WF', + label: 'Wallis and Futuna', + phone: '681', + flag: 'flag:wf-4x3', + }, + { code: 'WS', label: 'Samoa', phone: '685', flag: 'flag:ws-4x3' }, + { code: 'XK', label: 'Kosovo', phone: '383', flag: 'flag:xk-4x3' }, + { code: 'YE', label: 'Yemen', phone: '967', flag: 'flag:ye-4x3' }, + { + code: 'ZA', + label: 'South Africa', + phone: '27', + flag: 'flag:za-4x3', + }, + { code: 'ZM', label: 'Zambia', phone: '260', flag: 'flag:zm-4x3' }, + { code: 'ZW', label: 'Zimbabwe', phone: '263', flag: 'flag:zw-4x3' }, +]; diff --git a/apps/client/src/layouts/main-layout/MainLayout.tsx b/apps/client/src/layouts/main-layout/MainLayout.tsx index 732cca9..1af8445 100644 --- a/apps/client/src/layouts/main-layout/MainLayout.tsx +++ b/apps/client/src/layouts/main-layout/MainLayout.tsx @@ -1,24 +1,24 @@ -"use client"; +'use client'; -import { Drawer, drawerClasses } from "@mui/material"; -import Box from "@mui/material/Box"; -import Toolbar, { ToolbarOwnProps } from "@mui/material/Toolbar"; -import clsx from "clsx"; -import VibrantBackground from "components/common/VibrantBackground"; -import AppBar from "layouts/main-layout/app-bar"; -import Sidenav from "layouts/main-layout/sidenav"; -import { mainDrawerWidth } from "lib/constants"; -import { useSettingsContext } from "providers/SettingsProvider"; -import { PropsWithChildren, useMemo } from "react"; -import { sidenavVibrantStyle } from "theme/styles/vibrantNav"; -import NavProvider from "./NavProvider"; -import Footer from "./footer"; -import SidenavDrawerContent from "./sidenav/SidenavDrawerContent"; -import SlimSidenav from "./sidenav/SlimSidenav"; -import StackedSidenav from "./sidenav/StackedSidenav"; -import Topnav from "./topnav"; -import TopNavStacked from "./topnav/TopNavStacked"; -import TopnavSlim from "./topnav/TopnavSlim"; +import { PropsWithChildren, useMemo } from 'react'; +import { Drawer, drawerClasses } from '@mui/material'; +import Box from '@mui/material/Box'; +import Toolbar, { ToolbarOwnProps } from '@mui/material/Toolbar'; +import clsx from 'clsx'; +import AppBar from 'layouts/main-layout/app-bar'; +import Sidenav from 'layouts/main-layout/sidenav'; +import { mainDrawerWidth } from 'lib/constants'; +import { useSettingsContext } from 'providers/SettingsProvider'; +import { sidenavVibrantStyle } from 'theme/styles/vibrantNav'; +import VibrantBackground from 'components/common/VibrantBackground'; +import NavProvider from './NavProvider'; +import Footer from './footer'; +import SidenavDrawerContent from './sidenav/SidenavDrawerContent'; +import SlimSidenav from './sidenav/SlimSidenav'; +import StackedSidenav from './sidenav/StackedSidenav'; +import Topnav from './topnav'; +import TopNavStacked from './topnav/TopNavStacked'; +import TopnavSlim from './topnav/TopnavSlim'; const MainLayout = ({ children }: PropsWithChildren) => { const { @@ -39,48 +39,47 @@ const MainLayout = ({ children }: PropsWithChildren) => { }); }; - const toolbarVarint: ToolbarOwnProps["variant"] = useMemo(() => { - if (navigationMenuType !== "sidenav") { - if (topnavType === "slim") { - return "appbarSlim"; + const toolbarVarint: ToolbarOwnProps['variant'] = useMemo(() => { + if (navigationMenuType !== 'sidenav') { + if (topnavType === 'slim') { + return 'appbarSlim'; } - if (topnavType === "stacked") { - return "appbarStacked"; + if (topnavType === 'stacked') { + return 'appbarStacked'; } } - return "appbar"; + return 'appbar'; }, [navigationMenuType, topnavType]); return ( + sx={{ display: 'flex', zIndex: 1, position: 'relative' }} + > - {navigationMenuType === "sidenav" && } + {navigationMenuType === 'sidenav' && } - {(navigationMenuType === "sidenav" || - navigationMenuType === "combo") && ( + {(navigationMenuType === 'sidenav' || navigationMenuType === 'combo') && ( <> - {sidenavType === "default" && } - {sidenavType === "slim" && } - {sidenavType === "stacked" && } + {sidenavType === 'default' && } + {sidenavType === 'slim' && } + {sidenavType === 'stacked' && } )} - {(navigationMenuType === "topnav" || - navigationMenuType === "combo") && ( + {(navigationMenuType === 'topnav' || navigationMenuType === 'combo') && ( <> - {topnavType === "default" && } - {topnavType === "slim" && } - {topnavType === "stacked" && } + {topnavType === 'default' && } + {topnavType === 'slim' && } + {topnavType === 'stacked' && } )} { }} sx={[ { - display: { xs: "block", md: "none" }, + display: { xs: 'block', md: 'none' }, [`& .${drawerClasses.paper}`]: { pt: 3, - boxSizing: "border-box", + boxSizing: 'border-box', width: mainDrawerWidth.full, }, }, - navigationMenuType === "topnav" && { - display: { md: "block", lg: "none" }, + navigationMenuType === 'topnav' && { + display: { md: 'block', lg: 'none' }, }, - navColor === "vibrant" && sidenavVibrantStyle, - ]}> - {navColor === "vibrant" && } - + navColor === 'vibrant' && sidenavVibrantStyle, + ]} + > + {navColor === 'vibrant' && } + + ]} + > @@ -135,9 +136,10 @@ const MainLayout = ({ children }: PropsWithChildren) => { sx={[ { height: 1, - bgcolor: "background.default", + bgcolor: 'background.default', }, - ]}> + ]} + > {children} diff --git a/apps/client/src/layouts/main-layout/NavProvider.tsx b/apps/client/src/layouts/main-layout/NavProvider.tsx index 6a30d95..cf53ca4 100644 --- a/apps/client/src/layouts/main-layout/NavProvider.tsx +++ b/apps/client/src/layouts/main-layout/NavProvider.tsx @@ -16,6 +16,7 @@ import { mainDrawerWidth } from 'lib/constants'; import { useBreakpoints } from 'providers/BreakpointsProvider'; import { useSettingsContext } from 'providers/SettingsProvider'; import { COLLAPSE_NAVBAR, EXPAND_NAVBAR } from 'reducers/SettingsReducer'; +import paths from 'routes/paths'; import { SubMenuItem } from 'routes/sitemap'; interface NavContextInterface { @@ -47,6 +48,9 @@ const NavProvider = ({ children }: PropsWithChildren) => { } = useSettingsContext(); const isNestedItemOpen = (items: SubMenuItem[] = []) => { + if (pathname === paths.comingSoon) { + return false; + } const checkLink = (children: SubMenuItem) => { if ( `${children.path}` === pathname || diff --git a/apps/client/src/layouts/main-layout/common/ThemeToggler.tsx b/apps/client/src/layouts/main-layout/common/ThemeToggler.tsx index 5611645..1e1dc1f 100644 --- a/apps/client/src/layouts/main-layout/common/ThemeToggler.tsx +++ b/apps/client/src/layouts/main-layout/common/ThemeToggler.tsx @@ -1,6 +1,7 @@ 'use client'; import { useCallback, useRef } from 'react'; +import { usePathname, useRouter } from 'next/navigation'; import { Button } from '@mui/material'; import { useThemeMode } from 'hooks/useThemeMode'; import IconifyIcon from 'components/base/IconifyIcon'; @@ -12,12 +13,16 @@ interface ThemeTogglerProps { const ThemeToggler = ({ type = 'default' }: ThemeTogglerProps) => { const { isDark, setThemeMode } = useThemeMode(); const lastClickTimeRef = useRef(0); + const router = useRouter(); + const pathname = usePathname(); const icon = isDark ? `material-symbols${type === 'slim' ? '' : '-light'}:light-off-outline-rounded` : `material-symbols${type === 'slim' ? '' : '-light'}:lightbulb-outline-rounded`; const handleClick = useCallback(() => { + router.replace(pathname); + const now = Date.now(); if (now - lastClickTimeRef.current < 300) return; diff --git a/apps/client/src/layouts/main-layout/common/search-box/SearchResult.tsx b/apps/client/src/layouts/main-layout/common/search-box/SearchResult.tsx index 63501e8..ddd89df 100644 --- a/apps/client/src/layouts/main-layout/common/search-box/SearchResult.tsx +++ b/apps/client/src/layouts/main-layout/common/search-box/SearchResult.tsx @@ -24,7 +24,6 @@ import { } from '@mui/material'; import searchResult from 'data/search-result'; import IconifyIcon from 'components/base/IconifyIcon'; -import Image from 'components/base/Image'; import SearchTextField from './SearchTextField'; const SearchResult = ({ handleClose }: { handleClose: () => void }) => { @@ -193,7 +192,7 @@ const SearchResult = ({ handleClose }: { handleClose: () => void }) => { )} {file.image && ( - {file.name} + {file.name} )} diff --git a/apps/client/src/layouts/main-layout/sidenav/NavItem.tsx b/apps/client/src/layouts/main-layout/sidenav/NavItem.tsx index 559885d..387d324 100644 --- a/apps/client/src/layouts/main-layout/sidenav/NavItem.tsx +++ b/apps/client/src/layouts/main-layout/sidenav/NavItem.tsx @@ -15,6 +15,7 @@ import { cssVarRgba } from 'lib/utils'; import { useBreakpoints } from 'providers/BreakpointsProvider'; import { useSettingsContext } from 'providers/SettingsProvider'; import { COLLAPSE_NAVBAR } from 'reducers/SettingsReducer'; +import paths from 'routes/paths'; import { SubMenuItem } from 'routes/sitemap'; import IconifyIcon from 'components/base/IconifyIcon'; import { useNavContext } from '../NavProvider'; @@ -128,10 +129,11 @@ const NavItem = ({ item, level }: NavItemProps) => { onMouseLeave={sidenavCollapsed ? handleClose : undefined} aria-expanded={openPopperMenu} selected={ - pathname === item.path || - (item.selectionPrefix && pathname!.includes(item.selectionPrefix)) || - (sidenavCollapsed && sidenavType === 'default' && isNestedItemOpen(item.items)) || - (openItems[level] !== item.pathName && isNestedItemOpen(item.items)) + pathname !== paths.comingSoon && + (pathname === item.path || + (item.selectionPrefix && pathname!.includes(item.selectionPrefix)) || + (sidenavCollapsed && sidenavType === 'default' && isNestedItemOpen(item.items)) || + (openItems[level] !== item.pathName && isNestedItemOpen(item.items))) } sx={[ (theme) => ({ diff --git a/apps/client/src/layouts/main-layout/sidenav/SlimNavItem.tsx b/apps/client/src/layouts/main-layout/sidenav/SlimNavItem.tsx index 858226f..13e3c82 100644 --- a/apps/client/src/layouts/main-layout/sidenav/SlimNavItem.tsx +++ b/apps/client/src/layouts/main-layout/sidenav/SlimNavItem.tsx @@ -18,6 +18,7 @@ import List from '@mui/material/List'; import DocSearch from 'layouts/main-layout/sidenav/doc-search/DocSearch'; import { cssVarRgba } from 'lib/utils'; import { useSettingsContext } from 'providers/SettingsProvider'; +import paths from 'routes/paths'; import { SubMenuItem } from 'routes/sitemap'; import IconifyIcon from 'components/base/IconifyIcon'; import { useNavContext } from '../NavProvider'; @@ -75,9 +76,10 @@ const SlimNavItem = ({ item, level }: SlimNavItemProps) => { onClick={toggleCollapseItem} aria-expanded={openPopperMenu} selected={ - pathname === item.path || - (item.selectionPrefix && pathname!.includes(item.selectionPrefix)) || - isNestedItemOpen(item.items) + pathname !== paths.comingSoon && + (pathname === item.path || + (item.selectionPrefix && pathname!.includes(item.selectionPrefix)) || + isNestedItemOpen(item.items)) } sx={[ { @@ -133,7 +135,7 @@ const SlimNavItem = ({ item, level }: SlimNavItemProps) => { href={item.path} onClick={toggleCollapseItem} aria-expanded={openPopperMenu} - // selected={pathname === item.path} + selected={pathname !== paths.comingSoon && pathname === item.path} sx={[ { color: 'text.secondary', diff --git a/apps/client/src/layouts/main-layout/sidenav/StackedSidenav.tsx b/apps/client/src/layouts/main-layout/sidenav/StackedSidenav.tsx index ae94d76..463de16 100644 --- a/apps/client/src/layouts/main-layout/sidenav/StackedSidenav.tsx +++ b/apps/client/src/layouts/main-layout/sidenav/StackedSidenav.tsx @@ -1,6 +1,5 @@ 'use client'; - import { useEffect, useState } from 'react'; import { usePathname } from 'next/navigation'; import { @@ -45,8 +44,7 @@ const StackedSidenav = () => { const { currentBreakpoint } = useBreakpoints(); const { isDark } = useThemeMode(); - // const { data } = useSession(); - // const user = data?.user; + const user = null; const isMenuActive = (item: MenuItem) => { const checkLink = (subMenuItem: SubMenuItem) => { @@ -208,7 +206,7 @@ const StackedSidenav = () => { > @@ -219,7 +217,7 @@ const StackedSidenav = () => { textWrap: 'nowrap', }} > - {"USER NAME"} + name diff --git a/apps/client/src/layouts/main-layout/sidenav/index.tsx b/apps/client/src/layouts/main-layout/sidenav/index.tsx index 4fe5e6d..622fece 100644 --- a/apps/client/src/layouts/main-layout/sidenav/index.tsx +++ b/apps/client/src/layouts/main-layout/sidenav/index.tsx @@ -1,11 +1,21 @@ -import { Backdrop, useTheme } from '@mui/material'; +import { + Backdrop, + ListItem, + ListItemButton, + ListItemIcon, + ListItemText, + listItemTextClasses, + useTheme, +} from '@mui/material'; import Box from '@mui/material/Box'; +import Divider from '@mui/material/Divider'; import Drawer, { drawerClasses } from '@mui/material/Drawer'; +import Toolbar from '@mui/material/Toolbar'; import { useBreakpoints } from 'providers/BreakpointsProvider'; import { useSettingsContext } from 'providers/SettingsProvider'; import { sidenavVibrantStyle } from 'theme/styles/vibrantNav'; +import IconifyIcon from 'components/base/IconifyIcon'; import VibrantBackground from 'components/common/VibrantBackground'; -import SidenavCollapse from './SidenavCollapse'; import SidenavDrawerContent from './SidenavDrawerContent'; const Sidenav = () => { @@ -42,7 +52,6 @@ const Sidenav = () => { display: { xs: 'none', md: 'flex' }, flexDirection: 'column', [`& .${drawerClasses.paper}`]: { - overflow: 'visible', boxSizing: 'border-box', width: drawerWidth, border: 0, @@ -60,7 +69,71 @@ const Sidenav = () => { > {navColor === 'vibrant' && } - + + + + ({ + minWidth: 180, + flexDirection: 'row', + justifyContent: 'flex-start', + alignItems: 'center', + textAlign: 'left', + p: theme.spacing(0.75, 5.75), + })), + ]} + onClick={toggleNavbarCollapse} + > + + {sidenavCollapsed ? ( + + ) : ( + + )} + + + {!sidenavCollapsed && ( + + + {sidenavCollapsed ? 'Expand' : 'Collapse'} + + + )} + + + {currentBreakpoint === 'md' && ( diff --git a/apps/client/src/layouts/main-layout/topnav/NavItemPopover.tsx b/apps/client/src/layouts/main-layout/topnav/NavItemPopover.tsx index 92b345c..5f3b48a 100644 --- a/apps/client/src/layouts/main-layout/topnav/NavItemPopover.tsx +++ b/apps/client/src/layouts/main-layout/topnav/NavItemPopover.tsx @@ -11,6 +11,7 @@ import { Popover, popoverClasses, } from '@mui/material'; +import paths from 'routes/paths'; import { SubMenuItem } from 'routes/sitemap'; import IconifyIcon from 'components/base/IconifyIcon'; import { useNavContext } from '../NavProvider'; @@ -103,9 +104,10 @@ const NavitemPopover = ({ anchorEl, open, handleClose, items, level }: NavItemPo }, }} selected={ - pathname === item.path || - (item.selectionPrefix && pathname!.includes(item.selectionPrefix)) || - isNestedItemOpen(item.items) + pathname !== paths.comingSoon && + (pathname === item.path || + (item.selectionPrefix && pathname!.includes(item.selectionPrefix)) || + isNestedItemOpen(item.items)) } > { + const personalInfoValues: PersonalInfo = personalInfoData; + const workHistoryValues: WorkHistory[] = workHistory; + const educationHistoryValues: EducationHistory[] = educationHistory; + + return ( + + {children} + + ); +}; + +export const useAccounts = () => use(AccountsContext); + +export default AccountsProvider; diff --git a/apps/client/src/routes/paths.ts b/apps/client/src/routes/paths.ts index ec00a58..8a949a6 100644 --- a/apps/client/src/routes/paths.ts +++ b/apps/client/src/routes/paths.ts @@ -15,6 +15,8 @@ const paths = { defaultLoggedOut: `/${rootPaths.authRoot}/default/logged-out`, + account: `/${rootPaths.pagesRoot}/account`, + comingSoon: `/${rootPaths.pagesRoot}/coming-soon`, 404: `/${rootPaths.errorRoot}/404`, }; diff --git a/apps/client/src/routes/sitemap.ts b/apps/client/src/routes/sitemap.ts index 0b3d0ec..dc772ab 100644 --- a/apps/client/src/routes/sitemap.ts +++ b/apps/client/src/routes/sitemap.ts @@ -17,7 +17,7 @@ export interface SubMenuItem { export interface MenuItem { id: string; - key?: string; + key?: string; // used for the locale subheader: string; icon: string; iconSx?: SxProps; @@ -26,144 +26,70 @@ export interface MenuItem { const sitemap: MenuItem[] = [ { - id: 'pages', - subheader: 'Pages', - key: 'pages', - icon: 'material-symbols:view-quilt-outline', - items: [ - { - name: 'Error 404', - key: 'error_404', - pathName: 'error', - active: true, - icon: 'material-symbols:warning-outline-rounded', - path: paths[404], - }, - ], - }, - { - id: 'authentication', - subheader: 'Authentication', - key: 'authentication', - icon: 'material-symbols:security-rounded', + id: 'homepage', + subheader: 'Homepage', + key: 'homepage', + icon: 'material-symbols:data-exploration-outline-rounded', items: [ { - name: 'Login', - key: 'login', - icon: 'material-symbols:login', - path: paths.login, - pathName: 'login', - active: true, - }, - { - name: 'Sign up', - key: 'signup', - icon: 'material-symbols:person-add-outline', - path: paths.signup, - pathName: 'signup', - active: true, - }, - { - name: 'Forgot password', - key: 'forgot_password', - icon: 'material-symbols:key-outline', - path: paths.forgotPassword, - pathName: 'forgot-password', + name: 'E-commerce', + key: 'e_commerce', + path: paths.comingSoon, + pathName: 'e-commerce', + icon: 'material-symbols:shopping-cart-outline', active: true, }, ], }, { - id: 'misc', - subheader: 'Misc', - key: 'misc', - icon: 'material-symbols:dashboard-customize-outline-rounded', + id: 'apps', + subheader: 'Apps', + key: 'apps', + icon: 'material-symbols:widgets-outline-rounded', items: [ { - name: 'Multi level', - key: 'multi_level', - pathName: 'multi-level', - icon: 'material-symbols:layers-outline-rounded', + name: 'E-commerce', + key: 'e_commerce', + pathName: 'ecommerce', + icon: 'material-symbols:storefront-outline-rounded', active: true, + hasNew: true, items: [ { - name: 'Level two (1)', - key: 'level_two_1', - path: '#!', - pathName: 'multi-level-2', - active: true, - }, - { - name: 'Level two (2)', - key: 'level_two_2', - pathName: 'multi-level-3', + name: 'Admin', + key: 'admin', + pathName: 'admin', active: true, + hasNew: true, items: [ { - name: 'Level three (1)', - key: 'level_three_1', - path: '#!', - pathName: 'multi-level-item-3', + name: 'Product listing', + key: 'product_listing', + path: paths[404], + pathName: 'product-listing', active: true, }, { - name: 'Level three (2)', - key: 'level_three_2', - path: '#!', - pathName: 'multi-level-item-4', + name: 'Product list', + key: 'product_list', + path: paths[404], + pathName: 'product-list', active: true, }, ], }, { - name: 'Level two (3)', - key: 'level_two_3', - pathName: 'multi-level-4', + name: 'Customer', + key: 'customer', + pathName: 'customer', active: true, items: [ { - name: 'Level three (3)', - key: 'level_three_3', - path: '#!', - pathName: 'multi-level-item-6', - active: true, - }, - { - name: 'Level three (4)', - key: 'level_three_4', - pathName: 'multi-level-item-7', + name: 'Homepage', + key: 'homepage', + path: paths[404], + pathName: 'homepage', active: true, - items: [ - { - name: 'Level four (1)', - key: 'level_four_1', - path: '#!', - pathName: 'multi-level-item-8', - active: true, - }, - { - name: 'Level four (2)', - key: 'level_four_2', - pathName: 'multi-level-item-9', - active: true, - items: [ - { - name: 'Level five (1)', - key: 'level_five_1', - path: '#!', - pathName: 'multi-level-item-10', - active: true, - }, - { - name: 'Level five (2)', - key: 'level_five_2', - path: '#!', - pathName: 'multi-level-item-11', - active: true, - }, - ], - }, - ], }, ], }, @@ -171,6 +97,30 @@ const sitemap: MenuItem[] = [ }, ], }, + { + id: 'pages', + subheader: 'Pages', + key: 'pages', + icon: 'material-symbols:view-quilt-outline', + items: [ + { + name: 'Account', + key: 'account', + path: paths.account, + pathName: 'account', + active: true, + icon: 'material-symbols:admin-panel-settings-outline-rounded', + }, + { + name: 'Error 404', + key: 'error_404', + pathName: 'error', + active: true, + icon: 'material-symbols:warning-outline-rounded', + path: paths[404], + }, + ], + }, ]; export default sitemap; diff --git a/apps/client/src/types/accounts.ts b/apps/client/src/types/accounts.ts new file mode 100644 index 0000000..475db9a --- /dev/null +++ b/apps/client/src/types/accounts.ts @@ -0,0 +1,146 @@ +import { JSX, ReactNode } from 'react'; +import { StaticImageData } from 'next/image'; + +export interface AccountTab { + id?: number; + label: string; + title: string; + value: string; + icon: string; + panelIcon: string; + tabPanel: JSX.Element; +} + +export interface PersonalInfo { + firstName: string; + lastName: string; + userName: string; + birthDate: string; + country: string; + state: string; + city: string; + street: string; + zip: string; + phoneNumber: string; + primaryEmail: string; + secondaryEmail: string; +} + +export interface WorkHistory { + id?: number; + companyName: string; + companyLogo: string | StaticImageData; + designation: string; + location: string; + startDate: string; + endDate?: string; + currentlyWorking: boolean; +} + +export interface EducationHistory { + id?: number; + institutionName: string; + institutionLogo: string | StaticImageData; + subject: string; + location: string; + startDate: string; + endDate: string; +} + +export interface LoggedInDevice { + id: number; + name: string; + icon: string | StaticImageData; + location: string; + currentlyLoggedIn: boolean; + firstLoggedTime: Date; + lastLoggedTime: Date; + browsersAppsServices?: { + icon: string | StaticImageData; + name: string; + }[]; +} + +export interface ConnectedInDevice { + id: number; + securityKey: string; + deviceName: string; + connected: boolean; + used: boolean; + currentlyUsed: boolean; + lastUsedDate: Date; + deviceIcon: string; +} + +export interface Language { + id: number; + name: string; + label: string; +} + +export interface Notification { + name: string; + checked: boolean; + label: ReactNode; +} + +export interface NotificationMethodOptions { + newNotifications: boolean; + directNotifications: boolean; + postsEmailed: boolean; + notificationFrequency: 'Daily' | 'Weekly' | 'Periodically' | 'Off' | null; + feedback: boolean; + deals: boolean; + personalizedDeals: boolean; + updates: boolean; + accountSecurity: boolean; + packageUpdates: boolean; +} + +export interface CardInfo { + id?: number; + cardName: string; + cardNumber: string; + cardHolder: string; + expireDate: string; + subscriptions: number; + icon: string | StaticImageData; + cvc: string; +} + +export interface AddressInfo { + name: string; + phoneNumber: string; + emailAddress: string; + country: string; + state: string; + city: string; + street: string; + zip: string; + addressType: string; +} + +export interface Permission { + name: string; + checked: boolean; + label: ReactNode; +} + +export interface StorageCategory { + name: string; + icon?: string; + color?: string; + fileCount: number; + spaceUsedinKb: number; +} + +export interface Storage { + totalSpaceinKb: number; + totalSpaceUsedinKb: number; + categories: StorageCategory[]; +} + +export interface BackupSyncSettings { + name: string; + enabled: boolean; +} diff --git a/apps/client/src/types/common.ts b/apps/client/src/types/common.ts new file mode 100644 index 0000000..6afa1db --- /dev/null +++ b/apps/client/src/types/common.ts @@ -0,0 +1,8 @@ +export interface FileAttachment { + name: string; + size?: string; + src?: string; + format: string; + date?: string; + preview?: string; +} diff --git a/apps/client/src/types/countries.ts b/apps/client/src/types/countries.ts new file mode 100644 index 0000000..2246319 --- /dev/null +++ b/apps/client/src/types/countries.ts @@ -0,0 +1,6 @@ +export interface Country { + code: string; + label: string; + phone: string; + flag: string; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 83a58d7..e5094d2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -141,6 +141,9 @@ importers: react-i18next: specifier: ^16.1.0 version: 16.2.3(i18next@25.6.0(typescript@5.9.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + react-qr-code: + specifier: ^2.0.18 + version: 2.0.18(react@19.2.0) simplebar-core: specifier: ^1.3.2 version: 1.3.2 @@ -205,6 +208,9 @@ importers: prettier: specifier: ^3.6.2 version: 3.6.2 + react-dropzone: + specifier: ^14.3.8 + version: 14.3.8(react@19.2.0) typescript: specifier: ^5.9.3 version: 5.9.3 @@ -2619,6 +2625,10 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + attr-accept@2.2.5: + resolution: {integrity: sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==} + engines: {node: '>=4'} + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -3579,6 +3589,10 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + file-selector@2.1.2: + resolution: {integrity: sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==} + engines: {node: '>= 12'} + file-type@21.0.0: resolution: {integrity: sha512-ek5xNX2YBYlXhiUXui3D/BXa3LdqPmoLJ7rqEx2bKJ7EAUEfmXgW0Das7Dc6Nr9MvqaOnIqiPV0mZk/r/UpNAg==} engines: {node: '>=20'} @@ -5013,6 +5027,9 @@ packages: resolution: {integrity: sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==} engines: {node: '>=16.0.0'} + qr.js@0.0.0: + resolution: {integrity: sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==} + qs@6.14.0: resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} @@ -5042,6 +5059,12 @@ packages: peerDependencies: react: ^19.2.0 + react-dropzone@14.3.8: + resolution: {integrity: sha512-sBgODnq+lcA4P296DY4wacOZz3JFpD99fp+hb//iBO2HHnyeZU3FwWyXJ6salNpqQdsZrgMrotuko/BdJMV8Ug==} + engines: {node: '>= 10.13'} + peerDependencies: + react: '>= 16.8 || 18.0.0' + react-hook-form@7.65.0: resolution: {integrity: sha512-xtOzDz063WcXvGWaHgLNrNzlsdFgtUWcb32E6WFaGTd7kPZG3EeDusjdZfUsPwKCKVXy1ZlntifaHZ4l8pAsmw==} engines: {node: '>=18.0.0'} @@ -5073,6 +5096,11 @@ packages: react-is@19.2.0: resolution: {integrity: sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==} + react-qr-code@2.0.18: + resolution: {integrity: sha512-v1Jqz7urLMhkO6jkgJuBYhnqvXagzceg3qJUWayuCK/c6LTIonpWbwxR1f1APGd4xrW/QcQEovNrAojbUz65Tg==} + peerDependencies: + react: '*' + react-transition-group@4.4.5: resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} peerDependencies: @@ -8655,6 +8683,8 @@ snapshots: asynckit@0.4.0: {} + attr-accept@2.2.5: {} + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.1.0 @@ -9777,6 +9807,10 @@ snapshots: dependencies: flat-cache: 4.0.1 + file-selector@2.1.2: + dependencies: + tslib: 2.8.1 + file-type@21.0.0: dependencies: '@tokenizer/inflate': 0.2.7 @@ -11418,6 +11452,8 @@ snapshots: pvutils@1.1.5: {} + qr.js@0.0.0: {} + qs@6.14.0: dependencies: side-channel: 1.1.0 @@ -11449,6 +11485,13 @@ snapshots: react: 19.2.0 scheduler: 0.27.0 + react-dropzone@14.3.8(react@19.2.0): + dependencies: + attr-accept: 2.2.5 + file-selector: 2.1.2 + prop-types: 15.8.1 + react: 19.2.0 + react-hook-form@7.65.0(react@19.2.0): dependencies: react: 19.2.0 @@ -11470,6 +11513,12 @@ snapshots: react-is@19.2.0: {} + react-qr-code@2.0.18(react@19.2.0): + dependencies: + prop-types: 15.8.1 + qr.js: 0.0.0 + react: 19.2.0 + react-transition-group@4.4.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: '@babel/runtime': 7.28.4