Compare commits

...

7 Commits

45 changed files with 13069 additions and 533 deletions

1010
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -147,6 +147,10 @@
"harmonyClub": { "harmonyClub": {
"title": "Harmony Club", "title": "Harmony Club",
"description": "Encourage repeat purchases by sending discount codes and points to your customers." "description": "Encourage repeat purchases by sending discount codes and points to your customers."
},
"harmonyBook": {
"title": "Harmony Book",
"description": "Improve customer engagement and smooth the path to growth and development of your business by making the scheduling process smarter."
} }
} }
} }

View File

@@ -147,6 +147,10 @@
"harmonyClub": { "harmonyClub": {
"title": "هارمونی کلاب", "title": "هارمونی کلاب",
"description": "با ارسال کد تخفیف و امتیاز به مشتریان کسب و کارتان آنها را به خرید مجدد ترغیب کنید" "description": "با ارسال کد تخفیف و امتیاز به مشتریان کسب و کارتان آنها را به خرید مجدد ترغیب کنید"
},
"harmonyBook": {
"title": "هارمونی بوک",
"description": "با هوشمندسازی فرایند نوبت‌دهی، تعامل با مشتری را بهبود بخشیده و مسیر رشد و توسعه کسب‌و‌کارتان را هموارتر کنید"
} }
} }
} }

BIN
src/assets/book-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

BIN
src/assets/club-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 216 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 198 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 219 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 199 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 196 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 230 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 220 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,4 +1,4 @@
import { Menu, Stack, Typography, Box, Button } from '@mui/material'; import { Menu, Stack, Typography, Box, Button, lighten } from '@mui/material';
import { blue } from '@mui/material/colors'; import { blue } from '@mui/material/colors';
import { Icon } from '@harmony/kit'; import { Icon } from '@harmony/kit';
import { ArrowLeft, ArrowRight } from 'iconsax-react'; import { ArrowLeft, ArrowRight } from 'iconsax-react';
@@ -43,15 +43,13 @@ export default function ProductsMenu({
}, },
}} }}
> >
{/* 1. Header Link */}
<Box sx={{ px: 2, py: 1, bgcolor: blue[50] }}> <Box sx={{ px: 2, py: 1, bgcolor: blue[50] }}>
<Typography variant="body2" color="primary.main"> <Typography variant="body2" color="primary.main">
{t('products.menu.title')} {t('products.menu.title')}
</Typography> </Typography>
</Box> </Box>
<Box sx={{ px: 2, py: 1 }}> <Stack sx={{ px: 2, py: 1 }} spacing={1}>
{/* 2. Map through products to create MenuItems */}
{productsData.map((product) => ( {productsData.map((product) => (
<Stack <Stack
key={product.id} key={product.id}
@@ -60,7 +58,6 @@ export default function ProductsMenu({
alignItems="center" alignItems="center"
width="100%" width="100%"
> >
{/* Text Content */}
<Stack minWidth={0} direction="column" spacing={0.5} flexGrow={1}> <Stack minWidth={0} direction="column" spacing={0.5} flexGrow={1}>
<Typography variant="h6">{t(product.titleKey)}</Typography> <Typography variant="h6">{t(product.titleKey)}</Typography>
<Typography variant="body2" color="text.secondary"> <Typography variant="body2" color="text.secondary">
@@ -71,7 +68,6 @@ export default function ProductsMenu({
href={product.demoLink} href={product.demoLink}
target="_blank" target="_blank"
variant="text" variant="text"
color="club"
endIcon={ endIcon={
<Icon <Icon
Component={i18n.dir() === 'ltr' ? ArrowRight : ArrowLeft} Component={i18n.dir() === 'ltr' ? ArrowRight : ArrowLeft}
@@ -80,6 +76,11 @@ export default function ProductsMenu({
sx={{ sx={{
alignSelf: 'flex-start', alignSelf: 'flex-start',
width: 'unset', width: 'unset',
color: product.color,
':hover': {
bgcolor: lighten(product.color, 0.9),
},
}} }}
> >
{t('products.menu.getDemo')} {t('products.menu.getDemo')}
@@ -89,7 +90,7 @@ export default function ProductsMenu({
<Box sx={{ width: 69 }}>{product.LogoComponent}</Box> <Box sx={{ width: 69 }}>{product.LogoComponent}</Box>
</Stack> </Stack>
))} ))}
</Box> </Stack>
</Menu> </Menu>
); );
} }

View File

@@ -1,5 +1,7 @@
import Logo from '@/components/Logo'; import { Box } from '@mui/material';
import type { ReactElement } from 'react'; import type { ReactElement } from 'react';
import ClubLogo from '@/assets/club-logo.png';
import BookLogo from '@/assets/book-logo.png';
export interface Product { export interface Product {
id: string; id: string;
@@ -7,6 +9,7 @@ export interface Product {
descriptionKey: string; descriptionKey: string;
LogoComponent: ReactElement; LogoComponent: ReactElement;
demoLink: string; demoLink: string;
color: string;
} }
export const productsData: Product[] = [ export const productsData: Product[] = [
@@ -14,8 +17,29 @@ export const productsData: Product[] = [
id: 'harmony-club', id: 'harmony-club',
titleKey: 'products.harmonyClub.title', titleKey: 'products.harmonyClub.title',
descriptionKey: 'products.harmonyClub.description', descriptionKey: 'products.harmonyClub.description',
LogoComponent: <Logo isIcon boxSx={{ width: 69, height: 55 }} />, // Reference the component LogoComponent: (
demoLink: 'https://club.business-harmony.com', <Box
component="img"
src={ClubLogo}
sx={{ width: 69, aspectRatio: '1 / 1', objectFit: 'contain' }}
/>
), // Reference the component
demoLink: 'https://business-harmony.com/club/',
color: '#ff5722',
},
{
id: 'harmony-book',
titleKey: 'products.harmonyBook.title',
descriptionKey: 'products.harmonyBook.description',
LogoComponent: (
<Box
component="img"
src={BookLogo}
sx={{ width: 69, aspectRatio: '1 / 1', objectFit: 'contain', px: 0.5 }}
/>
), // Reference the component
demoLink: 'https://business-harmony.com/book/',
color: '#d3365d',
}, },
// add more products here // add more products here
]; ];

View File

@@ -20,8 +20,8 @@ export const AuthenticationCard = ({
}, },
mx: 2, mx: 2,
boxSizing: 'border-box', boxSizing: 'border-box',
maxWidth: 636, width: '100%',
maxWidth: 600,
...sx, ...sx,
}} }}
> >

View File

@@ -76,7 +76,9 @@ export function LoginRegisterForm({
setLoginRegisterValue(newValue); setLoginRegisterValue(newValue);
const strippedValue = newValue.startsWith('+') ? newValue.substring(1) : newValue; const strippedValue = newValue.startsWith('+')
? newValue.substring(1)
: newValue;
if (isNumeric(strippedValue) && strippedValue.length > 0) { if (isNumeric(strippedValue) && strippedValue.length > 0) {
setAuthType('phone'); setAuthType('phone');
} else { } else {
@@ -147,7 +149,7 @@ export function LoginRegisterForm({
newValue, newValue,
res.userStatus, res.userStatus,
res.totalSecondForOtpToExpire, res.totalSecondForOtpToExpire,
authType authType,
); );
} else { } else {
toast({ message: res.message, severity: 'error' }); toast({ message: res.message, severity: 'error' });
@@ -191,7 +193,12 @@ export function LoginRegisterForm({
helperText={inputError && t(error || '')} helperText={inputError && t(error || '')}
autoFocus autoFocus
slotProps={{ slotProps={{
htmlInput: { dir: 'auto', sx: { lineHeight: 1.5 } }, htmlInput: {
dir: 'auto',
sx: { lineHeight: 1.5 },
name: 'username',
autoComplete: 'username',
},
input: { input: {
endAdornment: i18n.dir() === 'rtl' && ( endAdornment: i18n.dir() === 'rtl' && (
<CountryCodeSelector <CountryCodeSelector

View File

@@ -84,14 +84,10 @@ export const InfoRowEdit = forwardRef(
} }
label={label} label={label}
error={ error={
name !== 'nationalCode' && touched[name] && (value.trim() === '' || !isValidName(value))
touched[name] &&
(value.trim() === '' || !isValidName(value))
} }
helperText={ helperText={
name !== 'nationalCode' && touched[name] && (value.trim() === '' || !isValidName(value))
touched[name] &&
(value.trim() === '' || !isValidName(value))
? t('settingForm.thisFieldIsRequired', { ns: 'setting' }) ? t('settingForm.thisFieldIsRequired', { ns: 'setting' })
: undefined : undefined
} }

View File

@@ -111,3 +111,127 @@
url('./assets/fonts/ttf/iranyekanwebextrablackfanum.ttf') url('./assets/fonts/ttf/iranyekanwebextrablackfanum.ttf')
format('truetype'); format('truetype');
} }
@font-face {
font-family: iranyekanEnNum;
font-style: normal;
font-weight: bold;
src: url('./assets/fonts/eot/iranyekanwebbold.eot');
src:
url('./assets/fonts/eot/iranyekanwebbold.eot?#iefix')
format('embedded-opentype'),
/* IE6-8 */ url('./assets/fonts/woff/iranyekanwebbold.woff') format('woff'),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/
url('./assets/fonts/woff2/iranyekanwebbold.woff2') format('woff2'),
/* FF39+,Chrome36+, Opera24+*/
url('./assets/fonts/ttf/iranyekanwebbold.ttf') format('truetype');
}
@font-face {
font-family: iranyekanEnNum;
font-style: normal;
font-weight: 100;
src: url('./assets/fonts/eot/iranyekanwebthin.eot');
src:
url('./assets/fonts/eot/iranyekanwebthin.eot?#iefix')
format('embedded-opentype'),
/* IE6-8 */ url('./assets/fonts/woff/iranyekanwebthin.woff') format('woff'),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/
url('./assets/fonts/woff2/iranyekanwebthin.woff2') format('woff2'),
/* FF39+,Chrome36+, Opera24+*/
url('./assets/fonts/ttf/iranyekanwebthin.ttf') format('truetype');
}
@font-face {
font-family: iranyekanEnNum;
font-style: normal;
font-weight: 300;
src: url('./assets/fonts/eot/iranyekanweblight.eot');
src:
url('./assets/fonts/eot/iranyekanweblight.eot?#iefix')
format('embedded-opentype'),
/* IE6-8 */ url('./assets/fonts/woff/iranyekanweblight.woff') format('woff'),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/
url('./assets/fonts/woff2/iranyekanweblight.woff2') format('woff2'),
/* FF39+,Chrome36+, Opera24+*/
url('./assets/fonts/ttf/iranyekanweblight.ttf') format('truetype');
}
@font-face {
font-family: iranyekanEnNum;
font-style: normal;
font-weight: normal;
src: url('./assets/fonts/eot/iranyekanwebregular.eot');
src:
url('./assets/fonts/eot/iranyekanwebregular.eot?#iefix')
format('embedded-opentype'),
/* IE6-8 */ url('./assets/fonts/woff/iranyekanwebregular.woff')
format('woff'),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/
url('./assets/fonts/woff2/iranyekanwebregular.woff2') format('woff2'),
/* FF39+,Chrome36+, Opera24+*/
url('./assets/fonts/ttf/iranyekanwebregular.ttf') format('truetype');
}
@font-face {
font-family: iranyekanEnNum;
font-style: normal;
font-weight: 500;
src: url('./assets/fonts/eot/iranyekanwebmedium.eot');
src:
url('./assets/fonts/eot/iranyekanwebmedium.eot?#iefix')
format('embedded-opentype'),
/* IE6-8 */ url('./assets/fonts/woff/iranyekanwebmedium.woff')
format('woff'),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/
url('./assets/fonts/woff2/iranyekanwebmedium.woff2') format('woff2'),
/* FF39+,Chrome36+, Opera24+*/
url('./assets/fonts/ttf/iranyekanwebmedium.ttf') format('truetype');
}
@font-face {
font-family: iranyekanEnNum;
font-style: normal;
font-weight: 800;
src: url('./assets/fonts/eot/iranyekanwebextrabold.eot');
src:
url('./assets/fonts/eot/iranyekanwebextrabold.eot?#iefix')
format('embedded-opentype'),
/* IE6-8 */ url('./assets/fonts/woff/iranyekanwebextrabold.woff')
format('woff'),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/
url('./assets/fonts/woff2/iranyekanwebextrabold.woff2') format('woff2'),
/* FF39+,Chrome36+, Opera24+*/
url('./assets/fonts/ttf/iranyekanwebextrabold.ttf') format('truetype');
}
@font-face {
font-family: iranyekanEnNum;
font-style: normal;
font-weight: 850;
src: url('./assets/fonts/eot/iranyekanwebblack.eot');
src:
url('./assets/fonts/eot/iranyekanwebblack.eot?#iefix')
format('embedded-opentype'),
/* IE6-8 */ url('./assets/fonts/woff/iranyekanwebblack.woff') format('woff'),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/
url('./assets/fonts/woff2/iranyekanwebblack.woff2') format('woff2'),
/* FF39+,Chrome36+, Opera24+*/
url('./assets/fonts/ttf/iranyekanwebblack.ttf') format('truetype');
}
@font-face {
font-family: iranyekanEnNum;
font-style: normal;
font-weight: 900;
src: url('./assets/fonts/eot/iranyekanwebextrablack.eot');
src:
url('./assets/fonts/eot/iranyekanwebextrablack.eot?#iefix')
format('embedded-opentype'),
/* IE6-8 */ url('./assets/fonts/woff/iranyekanwebextrablack.woff')
format('woff'),
/* FF3.6+, IE9, Chrome6+, Saf5.1+*/
url('./assets/fonts/woff2/iranyekanwebextrablack.woff2') format('woff2'),
/* FF39+,Chrome36+, Opera24+*/
url('./assets/fonts/ttf/iranyekanwebextrablack.ttf') format('truetype');
}

View File

@@ -11,6 +11,8 @@ export const CustomThemeProvider: React.FC<{ children: React.ReactNode }> = ({
const theme = useMemo(() => { const theme = useMemo(() => {
const direction = i18n.dir(i18n.language); const direction = i18n.dir(i18n.language);
const isEnglish = i18n.language?.startsWith('en');
const fontFamily = isEnglish ? 'iranyekanEnNum' : 'iranyekan';
return createTheme({ return createTheme({
direction: direction, direction: direction,
@@ -29,7 +31,10 @@ export const CustomThemeProvider: React.FC<{ children: React.ReactNode }> = ({
shape: { shape: {
borderRadius: 8, borderRadius: 8,
}, },
typography: typography, typography: {
fontFamily: [fontFamily, 'sans-serif'].join(','),
...typography,
},
components: { components: {
MuiButton: { MuiButton: {
defaultProps: { defaultProps: {
@@ -59,7 +64,7 @@ export const CustomThemeProvider: React.FC<{ children: React.ReactNode }> = ({
}, },
}, },
}); });
}, [i18n]); }, [i18n, i18n.language]);
return ( return (
<ThemeProvider theme={theme} defaultMode="light"> <ThemeProvider theme={theme} defaultMode="light">

View File

@@ -1,6 +1,5 @@
// No need for a function, just a static object // No need for a function, just a static object
export const typography = { export const typography = {
fontFamily: ['iranyekan', 'sans-serif'].join(','),
fontWeightRegular: 400, fontWeightRegular: 400,
fontWeightMedium: 500, fontWeightMedium: 500,
fontWeightBold: 700, fontWeightBold: 700,