diff --git a/package-lock.json b/package-lock.json index 720f619..c13cc97 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2228,9 +2228,7 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", - "optional": true, "os": [ "win32" ] @@ -2537,6 +2535,22 @@ "typescript": ">=4.8.4 <6.0.0" } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@typescript-eslint/utils": { "version": "8.44.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.44.1.tgz", @@ -2887,9 +2901,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -3139,6 +3150,7 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, "license": "MIT" }, "node_modules/conf": { @@ -4975,10 +4987,6 @@ } }, "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", @@ -6366,21 +6374,6 @@ "dev": true, "license": "ISC" }, - "node_modules/yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -6430,4 +6423,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/App.tsx b/src/App.tsx index 12661e1..483c7e7 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,7 +4,7 @@ import { LanguageManager } from '@/components/LanguageManager'; import { RouterProvider } from 'react-router-dom'; import { router } from '@/routes'; import { useAuth } from './hooks/useAuth'; -import { Loading } from './components/Loading'; +import { Loading } from './components/routes/Loading'; function App() { const { authFinished } = useAuth(); diff --git a/src/assets/logo_icon.svg b/src/assets/logo_icon.svg new file mode 100644 index 0000000..7f31134 --- /dev/null +++ b/src/assets/logo_icon.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/features/authentication/components/CountryCodeSelector.tsx b/src/components/CountryCodeSelector.tsx similarity index 94% rename from src/features/authentication/components/CountryCodeSelector.tsx rename to src/components/CountryCodeSelector.tsx index 2c96738..3bfcb91 100644 --- a/src/features/authentication/components/CountryCodeSelector.tsx +++ b/src/components/CountryCodeSelector.tsx @@ -12,7 +12,7 @@ import { useMemo, useRef, useState, type RefObject } from 'react'; import { ArrowDown2 } from 'iconsax-react'; import ReactCountryFlag from 'react-country-flag'; import { useTranslation } from 'react-i18next'; -import { countries, type Country } from '../../../data/countries'; +import { countries, type Country } from '../data/countries'; import type { CountryCode } from '@/types/commonTypes'; import { Icon } from '@rkheftan/harmony-ui'; import { LTRTypography } from '@/components/common/LTRTypography'; @@ -40,7 +40,7 @@ export function CountryCodeSelector({ const open = Boolean(anchorEl); const searchInputRef = useRef(null); const menuWidth = menuAnchor ? menuAnchor.clientWidth : 'auto'; - const { t } = useTranslation(['country', 'common']); + const { t, i18n } = useTranslation(['country', 'common']); const selectedCountry = countries.find((c) => c.phone === value) || countries[0]; @@ -106,7 +106,7 @@ export function CountryCodeSelector({ height: '100%', display: 'flex', alignItems: 'center', - flexDirection: 'row-reverse', + flexDirection: i18n.dir() === 'ltr' ? 'row-reverse' : 'row', gap: 0.25, pl: show ? 0.25 : 0, @@ -147,11 +147,11 @@ export function CountryCodeSelector({ open={open} onClose={handleClose} slotProps={{ - list: { + paper: { sx: { width: menuWidth, - height: '18.75rem', - p: 0, + maxHeight: '20rem', + overflow: 'hidden', }, }, transition: { onEntered: handleMenuEntered }, @@ -160,6 +160,7 @@ export function CountryCodeSelector({ transformOrigin={{ vertical: 'top', horizontal: 'left' }} > - + {filteredCountries.length === 0 ? ( diff --git a/src/components/Logo.tsx b/src/components/Logo.tsx index dbba376..d931070 100644 --- a/src/components/Logo.tsx +++ b/src/components/Logo.tsx @@ -1,7 +1,25 @@ import LogoSvg from '@/assets/logo.svg'; +import LogoIconSvg from '@/assets/logo_icon.svg'; +import { Box, type SxProps } from '@mui/material'; -function Logo() { - return ; +interface LogoProps { + boxSx?: SxProps; + isIcon?: boolean; +} + +function Logo({ boxSx, isIcon = false }: LogoProps) { + // TODO: handle transition + return ( + + ); } export default Logo; diff --git a/src/components/Toast.tsx b/src/components/Toast.tsx deleted file mode 100644 index d9376be..0000000 --- a/src/components/Toast.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Alert, Snackbar, type AlertColor } from '@mui/material'; -import { type PropsWithChildren } from 'react'; - -export interface ToastProps extends PropsWithChildren { - color: AlertColor | undefined; - open: boolean; - onClose: () => void; -} - -export const Toast = ({ color, open, onClose, children }: ToastProps) => { - return ( - `calc(100% - ${t.spacing(6)})`, maxWidth: '396px' }} - open={open} - onClose={onClose} - > - - {children} - - - ); -}; diff --git a/src/components/layout/ProductsMenu.tsx b/src/components/layout/ProductsMenu.tsx index cb9d650..fc146f6 100644 --- a/src/components/layout/ProductsMenu.tsx +++ b/src/components/layout/ProductsMenu.tsx @@ -85,9 +85,7 @@ export default function ProductsMenu({ - - - + {product.LogoComponent} ))} diff --git a/src/components/Loading.tsx b/src/components/routes/Loading.tsx similarity index 100% rename from src/components/Loading.tsx rename to src/components/routes/Loading.tsx diff --git a/src/components/NavigateWithToast.tsx b/src/components/routes/NavigateWithToast.tsx similarity index 100% rename from src/components/NavigateWithToast.tsx rename to src/components/routes/NavigateWithToast.tsx diff --git a/src/components/ProtectedRoute.tsx b/src/components/routes/ProtectedRoute.tsx similarity index 100% rename from src/components/ProtectedRoute.tsx rename to src/components/routes/ProtectedRoute.tsx diff --git a/src/data/products.ts b/src/data/products.tsx similarity index 58% rename from src/data/products.ts rename to src/data/products.tsx index cd82aee..fb5580f 100644 --- a/src/data/products.ts +++ b/src/data/products.tsx @@ -1,12 +1,12 @@ import Logo from '@/components/Logo'; -import { type FC } from 'react'; +import type { ReactElement } from 'react'; export interface Product { id: string; titleKey: string; descriptionKey: string; - LogoComponent: FC; - demoLink: string | null; + LogoComponent: ReactElement; + demoLink: string; } export const productsData: Product[] = [ @@ -14,8 +14,8 @@ export const productsData: Product[] = [ id: 'harmony-club', titleKey: 'products.harmonyClub.title', descriptionKey: 'products.harmonyClub.description', - LogoComponent: Logo, // Reference the component - demoLink: null, // FIXME: update this url + LogoComponent: , // Reference the component + demoLink: '', // FIXME: update this url }, // add more products here ]; diff --git a/src/features/authentication/components/AuthenticationSteps/CompleteSignUp.tsx b/src/features/authentication/components/AuthenticationSteps/CompleteSignUp.tsx index e85c694..4c8e229 100644 --- a/src/features/authentication/components/AuthenticationSteps/CompleteSignUp.tsx +++ b/src/features/authentication/components/AuthenticationSteps/CompleteSignUp.tsx @@ -3,7 +3,7 @@ import parsePhoneNumberFromString from 'libphonenumber-js'; import { useRef, useState, type Dispatch } from 'react'; import { useTranslation } from 'react-i18next'; import { AuthenticationCard } from '../AuthenticationCard'; -import { CountryCodeSelector } from '../CountryCodeSelector'; +import { CountryCodeSelector } from '../../../../components/CountryCodeSelector'; import { sendSmsOtp } from '../../api/authorizationAPI'; import type { CountryCode } from '@/types/commonTypes'; import { useApi } from '@/hooks/useApi'; diff --git a/src/features/authentication/components/AuthenticationSteps/LoginRegiserForm.tsx b/src/features/authentication/components/AuthenticationSteps/LoginRegiserForm.tsx index 159f6cb..eba878f 100644 --- a/src/features/authentication/components/AuthenticationSteps/LoginRegiserForm.tsx +++ b/src/features/authentication/components/AuthenticationSteps/LoginRegiserForm.tsx @@ -5,7 +5,7 @@ import { isNumeric } from '@/utils/regexes/isNumeric'; import type { AuthFactory, AuthType } from '../../types/authTypes'; import { isEmail } from '@/utils/regexes/isEmail'; import { AuthenticationCard } from '../AuthenticationCard'; -import { CountryCodeSelector } from '../CountryCodeSelector'; +import { CountryCodeSelector } from '../../../../components/CountryCodeSelector'; import type { LoginResult, UserStatus } from '../../types/userTypes'; import { getUserStatusByPhoneNumberOrEmail } from '../../api/authorizationAPI'; import type { CountryCode } from '@/types/commonTypes'; diff --git a/src/features/authentication/components/ForgetPassword/ForgettedPasswordInfo.tsx b/src/features/authentication/components/ForgetPassword/ForgettedPasswordInfo.tsx index 5b2df84..8ed49ff 100644 --- a/src/features/authentication/components/ForgetPassword/ForgettedPasswordInfo.tsx +++ b/src/features/authentication/components/ForgetPassword/ForgettedPasswordInfo.tsx @@ -5,7 +5,7 @@ import { isNumeric } from '@/utils/regexes/isNumeric'; import type { AuthType } from '../../types/authTypes'; import { isEmail } from '@/utils/regexes/isEmail'; import { AuthenticationCard } from '../AuthenticationCard'; -import { CountryCodeSelector } from '../CountryCodeSelector'; +import { CountryCodeSelector } from '../../../../components/CountryCodeSelector'; import type { CountryCode } from '@/types/commonTypes'; import { sendForgetPassCode } from '../../api/authorizationAPI'; import type { SendForgetPassCodeRequest } from '../../types/userTypes'; diff --git a/src/features/profile/components/CountryCodeSelector.tsx b/src/features/profile/components/CountryCodeSelector.tsx deleted file mode 100644 index 5796faa..0000000 --- a/src/features/profile/components/CountryCodeSelector.tsx +++ /dev/null @@ -1,213 +0,0 @@ -import { - Box, - InputAdornment, - ListItem, - ListItemIcon, - ListItemText, - Menu, - MenuItem, - TextField, - Typography, -} from '@mui/material'; -import { useMemo, useRef, useState, type RefObject } from 'react'; -import { ArrowDown2 } from 'iconsax-react'; -import ReactCountryFlag from 'react-country-flag'; -import { useTranslation } from 'react-i18next'; -import { countries, type Country } from '../../../data/countries'; -import type { CountryCode } from '@/types/commonTypes'; -import { Icon } from '@rkheftan/harmony-ui'; -import { LTRBox } from '@/components/common/LTRBox'; -import { Virtuoso } from 'react-virtuoso'; - -interface CountryCodeSelectorProps { - show: boolean; - value: CountryCode; - onChange: (newValue: CountryCode) => void; - menuAnchor: HTMLElement | null; - onCloseFocusRef: RefObject; -} - -export function CountryCodeSelector({ - show, - value, - onChange, - menuAnchor, - onCloseFocusRef, -}: CountryCodeSelectorProps) { - const [anchorEl, setAnchorEl] = useState(null); - const [searchTerm, setSearchTerm] = useState(''); - const open = Boolean(anchorEl); - const searchInputRef = useRef(null); - const menuWidth = menuAnchor ? menuAnchor.clientWidth : 'auto'; - const { t, i18n } = useTranslation(['country', 'common']); - - const selectedCountry = - countries.find((c) => c.phone === value) || countries[0]; - - const handleClick = () => setAnchorEl(menuAnchor); - - const handleClose = () => { - setTimeout(() => setAnchorEl(null), 0); - setTimeout(() => { - onCloseFocusRef.current?.focus(); - }, 100); - setSearchTerm(''); - }; - - const handleSelect = (country: Country) => { - onChange(country.phone); - handleClose(); - }; - - const handleMenuEntered = () => { - searchInputRef.current?.focus(); - }; - - const filteredCountries = useMemo( - () => - countries.filter( - (country) => - t(country.label, { ns: 'country' }) - .toLowerCase() - .includes(searchTerm.toLowerCase()) || - country.label.toLowerCase().includes(searchTerm.toLowerCase()) || - country.phone.includes(searchTerm), - ), - [searchTerm, t], - ); - - const initialIndex = useMemo(() => { - const index = filteredCountries.findIndex((c) => c.phone === value); - return Math.max(0, index); - }, [filteredCountries, value]); - - return ( - - - theme.transitions.create(['width', 'opacity'], { - duration: theme.transitions.duration.standard, - }), - overflow: 'hidden', - whiteSpace: 'nowrap', - height: '200%', - display: 'flex', - alignItems: 'center', - gap: 0.25, - pl: show ? 0.25 : 0, - '&:hover': { cursor: 'pointer' }, - }} - > - - - - {value} - - - - - - - setSearchTerm(e.target.value)} - /> - - - - {filteredCountries.length === 0 ? ( - - - - {t('messages.noResualtFound', { ns: 'common' })} - - - - ) : ( - ( - handleSelect(country)} - sx={{ justifyContent: 'space-between' }} - > - - - - - - - - - {country.phone} - - - )} - computeItemKey={(_, c) => c.code} - /> - )} - - - - - ); -} diff --git a/src/features/profile/components/userInformation/phoneNumber/PhoneEditForm.tsx b/src/features/profile/components/userInformation/phoneNumber/PhoneEditForm.tsx index 2c0d05c..882122c 100644 --- a/src/features/profile/components/userInformation/phoneNumber/PhoneEditForm.tsx +++ b/src/features/profile/components/userInformation/phoneNumber/PhoneEditForm.tsx @@ -13,7 +13,7 @@ import { Icon } from '@rkheftan/harmony-ui'; import { type PhoneEditFormProps } from '@/features/profile/types/settingsType'; import { useRef } from 'react'; import { Trans, useTranslation } from 'react-i18next'; -import { CountryCodeSelector } from '@/features/authentication/components/CountryCodeSelector'; +import { CountryCodeSelector } from '@/components/CountryCodeSelector'; import { LTRTypography } from '@/components/common/LTRTypography'; export default function PhoneEditForm({ diff --git a/src/routes/config.tsx b/src/routes/config.tsx index e9b4f82..f515ac1 100644 --- a/src/routes/config.tsx +++ b/src/routes/config.tsx @@ -1,5 +1,5 @@ import { Layout } from '@/components'; -import { NavigateWithToast } from '@/components/NavigateWithToast'; +import { NavigateWithToast } from '@/components/routes/NavigateWithToast'; import { ProfileProvider } from '@/features/profile/providers/ProfileProvider'; import { Calendar, diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 9980e7d..43888d8 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -1,8 +1,8 @@ import { Suspense, type ReactNode } from 'react'; import { createBrowserRouter, type RouteObject } from 'react-router-dom'; import { appRoutes, type RouteConfig } from './config'; -import { ProtectedRoute } from '@/components/ProtectedRoute'; -import { Loading } from '@/components/Loading'; +import { ProtectedRoute } from '@/components/routes/ProtectedRoute'; +import { Loading } from '@/components/routes/Loading'; /** * A recursive function to map our custom route config to the format