Implement internationalization for account settings and search components. Added translation support for various UI elements, including billing, notifications, and user dropdowns. Refactored search suggestions and no result messages to utilize localized text. Enhanced user experience by ensuring all relevant components display text based on selected language.

This commit is contained in:
2026-02-19 17:41:37 +03:30
parent 0844100613
commit 25344a8738
14 changed files with 646 additions and 415 deletions
+223 -1
View File
@@ -6,6 +6,8 @@
"close": "بستن" "close": "بستن"
}, },
"login": { "login": {
"title": "ورود",
"description": "ورود به حساب کاربری",
"welcome": "خوش آمدید به {templateName}! 👋🏻", "welcome": "خوش آمدید به {templateName}! 👋🏻",
"phoneStep": "شماره موبایل خود را برای دریافت کد OTP وارد کنید", "phoneStep": "شماره موبایل خود را برای دریافت کد OTP وارد کنید",
"otpStep": "کد OTP ارسال شده به موبایل خود را وارد کنید", "otpStep": "کد OTP ارسال شده به موبایل خود را وارد کنید",
@@ -211,6 +213,226 @@
"confirmDelete": "لطفاً تایید کنید که می‌خواهید حساب را حذف کنید", "confirmDelete": "لطفاً تایید کنید که می‌خواهید حساب را حذف کنید",
"saveChanges": "ذخیره تغییرات", "saveChanges": "ذخیره تغییرات",
"saving": "در حال ذخیره...", "saving": "در حال ذخیره...",
"reset": "بازنشانی" "reset": "بازنشانی",
"security": {
"changePassword": "تغییر رمز عبور",
"currentPassword": "رمز عبور فعلی",
"newPassword": "رمز عبور جدید",
"confirmNewPassword": "تأیید رمز عبور جدید",
"passwordRequirements": "الزامات رمز عبور",
"passwordReq1": "حداقل ۸ کاراکتر - هر چه بیشتر بهتر",
"passwordReq2": "حداقل یک حرف کوچک و یک حرف بزرگ",
"passwordReq3": "حداقل یک عدد، نماد یا کاراکتر فاصله",
"createApiKey": "ایجاد کلید API",
"apiKeyType": "نوع کلید API را انتخاب کنید",
"apiKeyName": "نام کلید API",
"createKey": "ایجاد کلید",
"fullControl": "کنترل کامل",
"modify": "تغییر",
"readExecute": "خواندن و اجرا",
"listFolderContents": "فهرست محتویات پوشه",
"readOnly": "فقط خواندن",
"readWrite": "خواندن و نوشتن"
},
"billing": {
"currentPlan": "پلن فعلی",
"yourPlanBasic": "پلن فعلی شما پایه است",
"simpleStart": "شروع ساده برای همه",
"activeUntil": "فعال تا {date}",
"subscriptionExpiry": "اعلان انقضای اشتراک ارسال می‌شود",
"perMonth": "{amount} در ماه",
"popular": "محبوب",
"standardPlan": "پلن استاندارد برای کسب‌وکارهای کوچک و متوسط",
"attention": "توجه شما را می‌خواهیم!",
"planRequiresUpdate": "پلن شما نیاز به بروزرسانی دارد",
"days": "روزها",
"daysProgress": "{current} از {total} روز",
"daysRemaining": "{count} روز تا بروزرسانی پلن باقی مانده",
"upgradePlan": "ارتقای پلن",
"cancelSubscription": "لغو اشتراک",
"billingAddress": "آدرس صورتحساب",
"companyName": "نام شرکت",
"billingEmail": "ایمیل صورتحساب",
"taxId": "شناسه مالیاتی",
"vatNumber": "شماره ارزش افزوده",
"mobileNumber": "شماره موبایل",
"country": "کشور",
"selectCountry": "انتخاب کشور",
"australia": "استرالیا",
"canada": "کانادا",
"france": "فرانسه",
"unitedKingdom": "بریتانیا",
"unitedStates": "آمریکا",
"state": "ایالت",
"zipCode": "کد پستی",
"discard": "انصراف"
},
"notifications": {
"recentDevices": "دستگاه‌های اخیر",
"permissionRequest": "برای نمایش اعلان‌ها به مجوز مرورگر نیاز داریم",
"requestPermission": "درخواست مجوز",
"type": "نوع",
"whenToSend": "چه زمانی اعلان ارسال شود؟",
"onlyWhenOnline": "فقط وقتی آنلاین هستم",
"anytime": "هر زمان",
"discard": "انصراف"
}
},
"search": {
"placeholder": "جستجو ⌘K",
"toNavigate": "برای ناوبری",
"toOpen": "برای باز کردن",
"toClose": "برای بستن",
"noResult": "نتیجه‌ای برای «{searchValue}» یافت نشد",
"trySearching": "جستجو برای",
"popularSearches": "جستجوهای پرطرفدار",
"sections": {
"dashboards": "داشبوردها",
"frontPages": "صفحات فرانت",
"apps": "اپلیکیشن‌ها",
"pages": "صفحات",
"formsAndCharts": "فرم‌ها و چارت‌ها",
"formsAndTables": "فرم‌ها و جداول",
"charts": "چارت‌ها",
"others": "سایر",
"foundation": "پایه",
"components": "کامپوننت‌ها"
},
"items": {
"analyticsDashboard": "داشبورد تحلیل",
"ecommerceDashboard": "داشبورد فروشگاه",
"academyDashboard": "داشبورد آکادمی",
"logisticsDashboard": "داشبورد لجستیک",
"landingFront": "صفحه اصلی فرانت",
"pricingFront": "قیمت‌گذاری فرانت",
"paymentFront": "پرداخت فرانت",
"checkoutFront": "تسویه فرانت",
"helpCenterFront": "مرکز راهنمایی فرانت",
"ecommerceDashboardApp": "فروشگاه - داشبورد",
"ecommerceProductList": "فروشگاه - فهرست محصولات",
"ecommerceAddProduct": "فروشگاه - افزودن محصول",
"ecommerceProductCategory": "فروشگاه - دسته‌بندی محصولات",
"ecommerceOrderList": "فروشگاه - فهرست سفارشات",
"ecommerceOrderDetails": "فروشگاه - جزئیات سفارش",
"ecommerceCustomerList": "فروشگاه - فهرست مشتریان",
"ecommerceCustomerDetails": "فروشگاه - جزئیات مشتری",
"ecommerceManageReviews": "فروشگاه - مدیریت نظرات",
"ecommerceReferrals": "فروشگاه - معرفی‌ها",
"ecommerceSettings": "فروشگاه - تنظیمات",
"academyDashboardApp": "آکادمی - داشبورد",
"academyMyCourses": "آکادمی - دوره‌های من",
"academyCourseDetails": "آکادمی - جزئیات دوره",
"logisticsDashboardApp": "لجستیک - داشبورد",
"logisticsFleet": "لجستیک - ناوگان",
"email": "ایمیل",
"chat": "چت",
"calendar": "تقویم",
"kanban": "کانبان",
"todo": "وظایف",
"invoiceList": "فهرست فاکتور",
"invoicePreview": "پیش‌نمایش فاکتور",
"invoiceAdd": "افزودن فاکتور",
"invoiceEdit": "ویرایش فاکتور",
"userList": "فهرست کاربران",
"userView": "مشاهده کاربر",
"roles": "نقش‌ها",
"rolesPermissions": "نقش‌ها و دسترسی‌ها",
"permissions": "دسترسی‌ها",
"userProfile": "پروفایل کاربر",
"formLayouts": "چیدمان فرم",
"formValidation": "اعتبارسنجی فرم",
"formWizard": "ویزارد فرم",
"apexCharts": "چارت Apex",
"analytics": "تحلیل‌ها",
"todo": "وظایف",
"accountSettings": "تنظیمات حساب",
"faq": "سوالات متداول",
"pricing": "قیمت‌گذاری",
"comingSoon": "به زودی",
"underMaintenance": "در حال تعمیر",
"pageNotFound404": "صفحه یافت نشد - 404",
"notAuthorized401": "غیرمجاز - 401",
"loginV1": "ورود نسخه 1",
"loginV2": "ورود نسخه 2",
"registerV1": "ثبت نام نسخه 1",
"registerV2": "ثبت نام نسخه 2",
"registerMultiSteps": "ثبت نام چند مرحله‌ای",
"forgotPasswordV1": "فراموشی رمز نسخه 1",
"forgotPasswordV2": "فراموشی رمز نسخه 2",
"resetPasswordV1": "بازنشانی رمز نسخه 1",
"resetPasswordV2": "بازنشانی رمز نسخه 2",
"verifyEmailV1": "تایید ایمیل نسخه 1",
"verifyEmailV2": "تایید ایمیل نسخه 2",
"twoStepsV1": "دو مرحله‌ای نسخه 1",
"twoStepsV2": "دو مرحله‌ای نسخه 2",
"wizardCheckout": "ویزارد تسویه",
"propertyListing": "فهرست املاک",
"createDeal": "ایجاد معامله",
"dialogExamples": "مثال‌های دیالوگ",
"basic": "پایه",
"advanced": "پیشرفته",
"statistics": "آمار",
"charts": "چارت‌ها",
"actions": "عملیات",
"reactTable": "جدول React",
"recharts": "Recharts",
"menuExamples": "مثال‌های منو",
"typography": "تایپوگرافی",
"colors": "رنگ‌ها",
"shadows": "سایه‌ها",
"icons": "آیکون‌ها",
"accordion": "آکاردئون",
"alerts": "هشدارها",
"avatars": "آواتارها",
"badges": "نشان‌ها",
"buttons": "دکمه‌ها",
"buttonGroup": "گروه دکمه",
"chips": "تراشه‌ها",
"dialogs": "دیالوگ‌ها",
"list": "فهرست",
"menu": "منو",
"pagination": "صفحه‌بندی",
"progress": "پیشرفت",
"ratings": "امتیازات",
"snackbar": "اسنک بار",
"swiper": "اسلایدر",
"tabs": "تب‌ها",
"timeline": "خط زمانی",
"toasts": "اعلان‌ها",
"moreComponents": "کامپوننت‌های بیشتر",
"textField": "فیلد متن",
"select": "انتخاب",
"checkbox": "چک‌باکس",
"radio": "رادیو",
"customInputs": "ورودی‌های سفارشی",
"textarea": "ناحیه متن",
"autocomplete": "خودتکمیل",
"dateTimePickers": "انتخابگر تاریخ و زمان",
"switch": "سوئیچ",
"fileUploader": "آپلود فایل",
"editor": "ویرایشگر",
"slider": "اسلایدر",
"muiTables": "جداول MUI"
}
},
"theme": {
"colorPalette": "پالت رنگ",
"previewMode": "حالت پیش‌نمایش",
"light": "روشن",
"dark": "تاریک",
"lightMode": "حالت روشن",
"darkMode": "حالت تاریک",
"main": "اصلی",
"palettes": {
"purple": "پالت بنفش",
"teal": "پالت فیروزه‌ای",
"orange": "پالت نارنجی",
"pink": "پالت صورتی",
"blue": "پالت آبی"
}
},
"userDropdown": {
"myProfile": "پروفایل من",
"logout": "خروج"
} }
} }
@@ -1,5 +1,6 @@
// Next Imports // Next Imports
import type { Metadata } from 'next' import type { Metadata } from 'next'
import { getTranslations } from 'next-intl/server'
// Component Imports // Component Imports
import Login from '@views/Login' import Login from '@views/Login'
@@ -7,9 +8,13 @@ import Login from '@views/Login'
// Server Action Imports // Server Action Imports
import { getServerMode } from '@core/utils/serverHelpers' import { getServerMode } from '@core/utils/serverHelpers'
export const metadata: Metadata = { export async function generateMetadata(): Promise<Metadata> {
title: 'Login', const t = await getTranslations('login')
description: 'Login to your account'
return {
title: t('title'),
description: t('description')
}
} }
const LoginPage = async () => { const LoginPage = async () => {
@@ -2,6 +2,7 @@
// React Imports // React Imports
import { useRef, useState, useMemo } from 'react' import { useRef, useState, useMemo } from 'react'
import { useTranslations } from 'next-intl'
// MUI Imports // MUI Imports
import Tooltip from '@mui/material/Tooltip' import Tooltip from '@mui/material/Tooltip'
@@ -26,6 +27,8 @@ import { useSettings } from '@core/hooks/useSettings'
import type { SystemMode } from '@core/types' import type { SystemMode } from '@core/types'
const ThemeColorDropdown = () => { const ThemeColorDropdown = () => {
const t = useTranslations('theme')
// States // States
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const [tooltipOpen, setTooltipOpen] = useState(false) const [tooltipOpen, setTooltipOpen] = useState(false)
@@ -84,7 +87,7 @@ const ThemeColorDropdown = () => {
return ( return (
<> <>
<Tooltip <Tooltip
title='Color Palette' title={t('colorPalette')}
onOpen={() => setTooltipOpen(true)} onOpen={() => setTooltipOpen(true)}
onClose={() => setTooltipOpen(false)} onClose={() => setTooltipOpen(false)}
open={open ? false : tooltipOpen ? true : false} open={open ? false : tooltipOpen ? true : false}
@@ -112,7 +115,7 @@ const ThemeColorDropdown = () => {
{/* Mode Preview Selection */} {/* Mode Preview Selection */}
<Box className='pis-4 pie-4 pbs-2 pbe-2'> <Box className='pis-4 pie-4 pbs-2 pbe-2'>
<Typography variant='caption' className='text-textSecondary uppercase'> <Typography variant='caption' className='text-textSecondary uppercase'>
Preview Mode {t('previewMode')}
</Typography> </Typography>
<Box className='flex gap-2 mts-2'> <Box className='flex gap-2 mts-2'>
<MenuItem <MenuItem
@@ -122,7 +125,7 @@ const ThemeColorDropdown = () => {
sx={{ minHeight: 'auto', py: 1 }} sx={{ minHeight: 'auto', py: 1 }}
> >
<i className='tabler-sun text-sm' /> <i className='tabler-sun text-sm' />
<span className='text-sm'>Light</span> <span className='text-sm'>{t('light')}</span>
</MenuItem> </MenuItem>
<MenuItem <MenuItem
className='flex-1 gap-2 rounded' className='flex-1 gap-2 rounded'
@@ -131,7 +134,7 @@ const ThemeColorDropdown = () => {
sx={{ minHeight: 'auto', py: 1 }} sx={{ minHeight: 'auto', py: 1 }}
> >
<i className='tabler-moon-stars text-sm' /> <i className='tabler-moon-stars text-sm' />
<span className='text-sm'>Dark</span> <span className='text-sm'>{t('dark')}</span>
</MenuItem> </MenuItem>
</Box> </Box>
</Box> </Box>
@@ -153,7 +156,7 @@ const ThemeColorDropdown = () => {
<Box <Box
className='is-8 bs-8 rounded-full border border-border flex items-center justify-center' className='is-8 bs-8 rounded-full border border-border flex items-center justify-center'
style={{ backgroundColor: palette.light.main }} style={{ backgroundColor: palette.light.main }}
title='Light Mode' title={t('lightMode')}
> >
<i className='tabler-sun text-[10px] text-white' style={{ opacity: 0.7 }} /> <i className='tabler-sun text-[10px] text-white' style={{ opacity: 0.7 }} />
</Box> </Box>
@@ -161,28 +164,28 @@ const ThemeColorDropdown = () => {
<Box <Box
className='is-8 bs-8 rounded-full border border-border flex items-center justify-center' className='is-8 bs-8 rounded-full border border-border flex items-center justify-center'
style={{ backgroundColor: palette.dark.main }} style={{ backgroundColor: palette.dark.main }}
title='Dark Mode' title={t('darkMode')}
> >
<i className='tabler-moon-stars text-[10px] text-white' style={{ opacity: 0.7 }} /> <i className='tabler-moon-stars text-[10px] text-white' style={{ opacity: 0.7 }} />
</Box> </Box>
</Box> </Box>
<Box className='flex flex-col flex-1'> <Box className='flex flex-col flex-1'>
<span className='text-sm font-medium'>{palette.name}</span> <span className='text-sm font-medium'>{t(`palettes.${palette.paletteKey}`)}</span>
<Box className='flex items-center gap-1 mts-1'> <Box className='flex items-center gap-1 mts-1'>
<Box <Box
className='is-4 bs-4 rounded-full border border-border' className='is-4 bs-4 rounded-full border border-border'
style={{ backgroundColor: colors.main }} style={{ backgroundColor: colors.main }}
title='Main' title={t('main')}
/> />
<Box <Box
className='is-4 bs-4 rounded-full border border-border' className='is-4 bs-4 rounded-full border border-border'
style={{ backgroundColor: colors.light }} style={{ backgroundColor: colors.light }}
title='Light' title={t('light')}
/> />
<Box <Box
className='is-4 bs-4 rounded-full border border-border' className='is-4 bs-4 rounded-full border border-border'
style={{ backgroundColor: colors.dark }} style={{ backgroundColor: colors.dark }}
title='Dark' title={t('dark')}
/> />
</Box> </Box>
</Box> </Box>
@@ -6,6 +6,7 @@ import type { MouseEvent } from 'react'
// Next Imports // Next Imports
import { useRouter } from 'next/navigation' import { useRouter } from 'next/navigation'
import { useTranslations } from 'next-intl'
// MUI Imports // MUI Imports
import { styled } from '@mui/material/styles' import { styled } from '@mui/material/styles'
@@ -38,6 +39,8 @@ const BadgeContentSpan = styled('span')({
}) })
const UserDropdown = () => { const UserDropdown = () => {
const t = useTranslations('userDropdown')
// States // States
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
@@ -127,7 +130,7 @@ const UserDropdown = () => {
<Divider className='mlb-1' /> <Divider className='mlb-1' />
<MenuItem className='mli-2 gap-3' onClick={e => handleDropdownClose(e, '/pages/account-settings')}> <MenuItem className='mli-2 gap-3' onClick={e => handleDropdownClose(e, '/pages/account-settings')}>
<i className='tabler-user' /> <i className='tabler-user' />
<Typography color='text.primary'>My Profile</Typography> <Typography color='text.primary'>{t('myProfile')}</Typography>
</MenuItem> </MenuItem>
<div className='flex items-center plb-2 pli-3'> <div className='flex items-center plb-2 pli-3'>
<Button <Button
@@ -139,7 +142,7 @@ const UserDropdown = () => {
onClick={handleUserLogout} onClick={handleUserLogout}
sx={{ '& .MuiButton-endIcon': { marginInlineStart: 1.5 } }} sx={{ '& .MuiButton-endIcon': { marginInlineStart: 1.5 } }}
> >
Logout {t('logout')}
</Button> </Button>
</div> </div>
</MenuList> </MenuList>
@@ -1,13 +1,16 @@
'use client'
// Next Imports // Next Imports
import Link from 'next/link' import Link from 'next/link'
import { useTranslations } from 'next-intl'
// Third-party Imports // Third-party Imports
import classnames from 'classnames' import classnames from 'classnames'
type DefaultSuggestionsType = { type DefaultSuggestionsType = {
sectionLabel: string sectionLabelKey: string
items: { items: {
label: string labelKey: string
href: string href: string
icon?: string icon?: string
}[] }[]
@@ -15,89 +18,40 @@ type DefaultSuggestionsType = {
const defaultSuggestions: DefaultSuggestionsType[] = [ const defaultSuggestions: DefaultSuggestionsType[] = [
{ {
sectionLabel: 'Popular Searches', sectionLabelKey: 'popularSearches',
items: [ items: [
{ { labelKey: 'analytics', href: '/dashboards/analytics', icon: 'tabler-trending-up' },
label: 'Analytics', { labelKey: 'ecommerceDashboard', href: '/dashboards/ecommerce', icon: 'tabler-shopping-cart' },
href: '/dashboards/analytics', { labelKey: 'userList', href: '/apps/user/list', icon: 'tabler-file-description' }
icon: 'tabler-trending-up'
},
{
label: 'eCommerce',
href: '/dashboards/ecommerce',
icon: 'tabler-shopping-cart'
},
{
label: 'User List',
href: '/apps/user/list',
icon: 'tabler-file-description'
}
] ]
}, },
{ {
sectionLabel: 'Apps', sectionLabelKey: 'apps',
items: [ items: [
{ { labelKey: 'calendar', href: '/apps/calendar', icon: 'tabler-calendar' },
label: 'Calendar', { labelKey: 'invoiceList', href: '/apps/invoice/list', icon: 'tabler-file-info' },
href: '/apps/calendar', { labelKey: 'userList', href: '/apps/user/list', icon: 'tabler-file-invoice' },
icon: 'tabler-calendar' { labelKey: 'rolesPermissions', href: '/apps/roles', icon: 'tabler-lock' }
},
{
label: 'Invoice List',
href: '/apps/invoice/list',
icon: 'tabler-file-info'
},
{
label: 'User List',
href: '/apps/user/list',
icon: 'tabler-file-invoice'
},
{
label: 'Roles & Permissions',
href: '/apps/roles',
icon: 'tabler-lock'
}
] ]
}, },
{ {
sectionLabel: 'Pages', sectionLabelKey: 'pages',
items: [ items: [{ labelKey: 'userProfile', href: '/pages/user-profile', icon: 'tabler-user' }]
{
label: 'User Profile',
href: '/pages/user-profile',
icon: 'tabler-user'
}
]
}, },
{ {
sectionLabel: 'Forms & Charts', sectionLabelKey: 'formsAndCharts',
items: [ items: [
{ { labelKey: 'formLayouts', href: '/forms/form-layouts', icon: 'tabler-layout' },
label: 'Form Layouts', { labelKey: 'formValidation', href: '/forms/form-validation', icon: 'tabler-checkup-list' },
href: '/forms/form-layouts', { labelKey: 'formWizard', href: '/forms/form-wizard', icon: 'tabler-git-merge' },
icon: 'tabler-layout' { labelKey: 'apexCharts', href: '/charts/apex-charts', icon: 'tabler-chart-ppf' }
},
{
label: 'Form Validation',
href: '/forms/form-validation',
icon: 'tabler-checkup-list'
},
{
label: 'Form Wizard',
href: '/forms/form-wizard',
icon: 'tabler-git-merge'
},
{
label: 'Apex Charts',
href: '/charts/apex-charts',
icon: 'tabler-chart-ppf'
}
] ]
} }
] ]
const DefaultSuggestions = ({ setOpen }: { setOpen: (value: boolean) => void }) => { const DefaultSuggestions = ({ setOpen }: { setOpen: (value: boolean) => void }) => {
const t = useTranslations('search')
return ( return (
<div className='flex grow flex-wrap gap-x-[48px] gap-y-8 plb-14 pli-16 overflow-y-auto overflow-x-hidden bs-full'> <div className='flex grow flex-wrap gap-x-[48px] gap-y-8 plb-14 pli-16 overflow-y-auto overflow-x-hidden bs-full'>
{defaultSuggestions.map((section, index) => ( {defaultSuggestions.map((section, index) => (
@@ -106,7 +60,9 @@ const DefaultSuggestions = ({ setOpen }: { setOpen: (value: boolean) => void })
className='flex flex-col justify-center overflow-x-hidden gap-4 basis-full sm:basis-[calc((100%-3rem)/2)]' className='flex flex-col justify-center overflow-x-hidden gap-4 basis-full sm:basis-[calc((100%-3rem)/2)]'
> >
<p className='text-xs leading-[1.16667] uppercase text-textDisabled tracking-[0.8px]'> <p className='text-xs leading-[1.16667] uppercase text-textDisabled tracking-[0.8px]'>
{section.sectionLabel} {section.sectionLabelKey === 'popularSearches'
? t('popularSearches')
: t(`sections.${section.sectionLabelKey}`)}
</p> </p>
<ul className='flex flex-col gap-4'> <ul className='flex flex-col gap-4'>
{section.items.map((item, i) => ( {section.items.map((item, i) => (
@@ -117,7 +73,7 @@ const DefaultSuggestions = ({ setOpen }: { setOpen: (value: boolean) => void })
onClick={() => setOpen(false)} onClick={() => setOpen(false)}
> >
{item.icon && <i className={classnames(item.icon, 'flex text-xl')} />} {item.icon && <i className={classnames(item.icon, 'flex text-xl')} />}
<p className='text-[15px] leading-[1.4667] truncate'>{item.label}</p> <p className='text-[15px] leading-[1.4667] truncate'>{t(`items.${item.labelKey}`)}</p>
</Link> </Link>
</li> </li>
))} ))}
@@ -1,36 +1,32 @@
'use client'
// Next Imports // Next Imports
import Link from 'next/link' import Link from 'next/link'
import { useTranslations } from 'next-intl'
// Third-party Imports // Third-party Imports
import classnames from 'classnames' import classnames from 'classnames'
type NoResultData = { type NoResultData = {
label: string labelKey: string
href: string href: string
icon: string icon: string
} }
const noResultData: NoResultData[] = [ const noResultData: NoResultData[] = [
{ { labelKey: 'analytics', href: '/dashboards/analytics', icon: 'tabler-chart-pie-2' },
label: 'Analytics', { labelKey: 'userProfile', href: '/pages/user-profile', icon: 'tabler-user' }
href: '/dashboards/analytics',
icon: 'tabler-chart-pie-2'
},
{
label: 'User Profile',
href: '/pages/user-profile',
icon: 'tabler-user'
},
] ]
const NoResult = ({ searchValue, setOpen }: { searchValue: string; setOpen: (value: boolean) => void }) => { const NoResult = ({ searchValue, setOpen }: { searchValue: string; setOpen: (value: boolean) => void }) => {
const t = useTranslations('search')
return ( return (
<div className='flex items-center justify-center grow flex-wrap plb-14 pli-16 overflow-y-auto overflow-x-hidden bs-full'> <div className='flex items-center justify-center grow flex-wrap plb-14 pli-16 overflow-y-auto overflow-x-hidden bs-full'>
<div className='flex flex-col items-center'> <div className='flex flex-col items-center'>
<i className='tabler-file-alert text-[64px] mbe-2.5' /> <i className='tabler-file-alert text-[64px] mbe-2.5' />
<p className='text-lg font-medium leading-[1.55556] mbe-11'>{`No result for "${searchValue}"`}</p> <p className='text-lg font-medium leading-[1.55556] mbe-11'>{t('noResult', { searchValue })}</p>
<p className='text-[15px] leading-[1.4667] mbe-4 text-textDisabled'>Try searching for</p> <p className='text-[15px] leading-[1.4667] mbe-4 text-textDisabled'>{t('trySearching')}</p>
<ul className='flex flex-col self-start gap-[18px]'> <ul className='flex flex-col self-start gap-[18px]'>
{noResultData.map((item, index) => ( {noResultData.map((item, index) => (
<li key={index} className='flex items-center'> <li key={index} className='flex items-center'>
@@ -40,7 +36,7 @@ const NoResult = ({ searchValue, setOpen }: { searchValue: string; setOpen: (val
onClick={() => setOpen(false)} onClick={() => setOpen(false)}
> >
<i className={classnames(item.icon, 'text-xl')} /> <i className={classnames(item.icon, 'text-xl')} />
<p className='text-[15px] leading-[1.4667] truncate'>{item.label}</p> <p className='text-[15px] leading-[1.4667] truncate'>{t(`items.${item.labelKey}`)}</p>
</Link> </Link>
</li> </li>
))} ))}
+36 -27
View File
@@ -1,11 +1,12 @@
'use client' 'use client'
// React Imports // React Imports
import { useEffect, useState } from 'react' import { useEffect, useMemo, useState } from 'react'
import type { ReactNode } from 'react' import type { ReactNode } from 'react'
// Next Imports // Next Imports
import { useRouter, usePathname } from 'next/navigation' import { useRouter, usePathname } from 'next/navigation'
import { useTranslations } from 'next-intl'
// MUI Imports // MUI Imports
import IconButton from '@mui/material/IconButton' import IconButton from '@mui/material/IconButton'
@@ -52,28 +53,6 @@ type SearchItemProps = {
onSelect?: () => void onSelect?: () => void
} }
// Transform the data to group items by their sections
const transformedData = data.reduce((acc: Section[], item) => {
const existingSection = acc.find(section => section.title === item.section)
const newItem = {
id: item.id,
name: item.name,
url: item.url,
excludeLang: item.excludeLang,
icon: item.icon,
shortcut: item.shortcut
}
if (existingSection) {
existingSection.items.push(newItem)
} else {
acc.push({ title: item.section, items: [newItem] })
}
return acc
}, [])
// SearchItem Component for introduce the shortcut keys // SearchItem Component for introduce the shortcut keys
const SearchItem = ({ children, shortcut, value, currentPath, url, onSelect = () => {} }: SearchItemProps) => { const SearchItem = ({ children, shortcut, value, currentPath, url, onSelect = () => {} }: SearchItemProps) => {
return ( return (
@@ -108,6 +87,8 @@ const getFilteredResults = (sections: Section[]) => {
// Footer component for the search menu // Footer component for the search menu
const CommandFooter = () => { const CommandFooter = () => {
const t = useTranslations('search')
return ( return (
<div cmdk-footer=''> <div cmdk-footer=''>
<div className='flex items-center gap-1'> <div className='flex items-center gap-1'>
@@ -117,23 +98,25 @@ const CommandFooter = () => {
<kbd> <kbd>
<i className='tabler-arrow-down text-base' /> <i className='tabler-arrow-down text-base' />
</kbd> </kbd>
<span>to navigate</span> <span>{t('toNavigate')}</span>
</div> </div>
<div className='flex items-center gap-1'> <div className='flex items-center gap-1'>
<kbd> <kbd>
<i className='tabler-corner-down-left text-base' /> <i className='tabler-corner-down-left text-base' />
</kbd> </kbd>
<span>to open</span> <span>{t('toOpen')}</span>
</div> </div>
<div className='flex items-center gap-1'> <div className='flex items-center gap-1'>
<kbd>esc</kbd> <kbd>esc</kbd>
<span>to close</span> <span>{t('toClose')}</span>
</div> </div>
</div> </div>
) )
} }
const NavSearch = () => { const NavSearch = () => {
const t = useTranslations('search')
// States // States
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const [searchValue, setSearchValue] = useState('') const [searchValue, setSearchValue] = useState('')
@@ -144,6 +127,32 @@ const NavSearch = () => {
const { settings } = useSettings() const { settings } = useSettings()
const { isBreakpointReached } = useVerticalNav() const { isBreakpointReached } = useVerticalNav()
// Transform the data to group items by their sections (with translations)
const transformedData = useMemo(() => {
return data.reduce((acc: Section[], item) => {
const sectionTitle = t(`sections.${item.sectionKey}`)
const itemName = t(`items.${item.nameKey}`)
const existingSection = acc.find(section => section.title === sectionTitle)
const newItem: Item = {
id: item.id,
name: itemName,
url: item.url,
excludeLang: item.excludeLang,
icon: item.icon,
shortcut: item.shortcut
}
if (existingSection) {
existingSection.items.push(newItem)
} else {
acc.push({ title: sectionTitle, items: [newItem] })
}
return acc
}, [])
}, [t])
// When an item is selected from the search results // When an item is selected from the search results
const onSearchItemSelect = (item: Item) => { const onSearchItemSelect = (item: Item) => {
item.url.startsWith('http') item.url.startsWith('http')
@@ -214,7 +223,7 @@ const NavSearch = () => {
<IconButton className='text-textPrimary' onClick={() => setOpen(true)}> <IconButton className='text-textPrimary' onClick={() => setOpen(true)}>
<i className='tabler-search text-2xl' /> <i className='tabler-search text-2xl' />
</IconButton> </IconButton>
<div className='whitespace-nowrap select-none text-textDisabled'>Search K</div> <div className='whitespace-nowrap select-none text-textDisabled'>{t('placeholder')}</div>
</div> </div>
)} )}
<CommandDialog open={open} onOpenChange={setOpen}> <CommandDialog open={open} onOpenChange={setOpen}>
+12
View File
@@ -6,7 +6,9 @@ export type ColorPalette = {
export type PrimaryColorConfig = { export type PrimaryColorConfig = {
id: string id: string
paletteKey: string
name: string name: string
main?: string
light: ColorPalette light: ColorPalette
dark: ColorPalette dark: ColorPalette
} }
@@ -15,7 +17,9 @@ export type PrimaryColorConfig = {
const primaryColorConfig: PrimaryColorConfig[] = [ const primaryColorConfig: PrimaryColorConfig[] = [
{ {
id: 'palette-1', id: 'palette-1',
paletteKey: 'purple',
name: 'Purple Palette', name: 'Purple Palette',
main: '#7367F0',
light: { light: {
main: '#7367F0', main: '#7367F0',
light: '#8F85F3', light: '#8F85F3',
@@ -29,7 +33,9 @@ const primaryColorConfig: PrimaryColorConfig[] = [
}, },
{ {
id: 'palette-2', id: 'palette-2',
paletteKey: 'teal',
name: 'Teal Palette', name: 'Teal Palette',
main: '#0D9394',
light: { light: {
main: '#0D9394', main: '#0D9394',
light: '#4EB0B1', light: '#4EB0B1',
@@ -43,7 +49,9 @@ const primaryColorConfig: PrimaryColorConfig[] = [
}, },
{ {
id: 'palette-3', id: 'palette-3',
paletteKey: 'orange',
name: 'Orange Palette', name: 'Orange Palette',
main: '#FFAB1D',
light: { light: {
main: '#FFAB1D', main: '#FFAB1D',
light: '#FFC25A', light: '#FFC25A',
@@ -57,7 +65,9 @@ const primaryColorConfig: PrimaryColorConfig[] = [
}, },
{ {
id: 'palette-4', id: 'palette-4',
paletteKey: 'pink',
name: 'Pink Palette', name: 'Pink Palette',
main: '#EB3D63',
light: { light: {
main: '#EB3D63', main: '#EB3D63',
light: '#F0718D', light: '#F0718D',
@@ -71,7 +81,9 @@ const primaryColorConfig: PrimaryColorConfig[] = [
}, },
{ {
id: 'palette-5', id: 'palette-5',
paletteKey: 'blue',
name: 'Blue Palette', name: 'Blue Palette',
main: '#2092EC',
light: { light: {
main: '#2092EC', main: '#2092EC',
light: '#5CAFF1', light: '#5CAFF1',
+223 -223
View File
File diff suppressed because it is too large Load Diff
@@ -2,6 +2,7 @@
// React Imports // React Imports
import { useState } from 'react' import { useState } from 'react'
import { useTranslations } from 'next-intl'
// MUI Imports // MUI Imports
import Grid from '@mui/material/Grid2' import Grid from '@mui/material/Grid2'
@@ -16,32 +17,35 @@ import InputAdornment from '@mui/material/InputAdornment'
import CustomTextField from '@core/components/mui/TextField' import CustomTextField from '@core/components/mui/TextField'
const Address = () => { const Address = () => {
const t = useTranslations('accountSettings')
const tBilling = useTranslations('accountSettings.billing')
// States // States
const [state, setState] = useState('') const [state, setState] = useState('')
return ( return (
<Card> <Card>
<CardHeader title='Billing Address' /> <CardHeader title={tBilling('billingAddress')} />
<CardContent> <CardContent>
<form> <form>
<Grid container spacing={6}> <Grid container spacing={6}>
<Grid size={{ xs: 12, sm: 6 }}> <Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField fullWidth label='Company Name' variant='outlined' placeholder='Pixinvent' /> <CustomTextField fullWidth label={tBilling('companyName')} variant='outlined' placeholder='Pixinvent' />
</Grid> </Grid>
<Grid size={{ xs: 12, sm: 6 }}> <Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField fullWidth label='Billing Email' variant='outlined' placeholder='john.doe@example.com' /> <CustomTextField fullWidth label={tBilling('billingEmail')} variant='outlined' placeholder='john.doe@example.com' />
</Grid> </Grid>
<Grid size={{ xs: 12, sm: 6 }}> <Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField fullWidth label='TAX ID' variant='outlined' placeholder='Enter TAX ID' /> <CustomTextField fullWidth label={tBilling('taxId')} variant='outlined' placeholder='Enter TAX ID' />
</Grid> </Grid>
<Grid size={{ xs: 12, sm: 6 }}> <Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField fullWidth label='VAT Number' variant='outlined' placeholder='Enter VAT Number' /> <CustomTextField fullWidth label={tBilling('vatNumber')} variant='outlined' placeholder='Enter VAT Number' />
</Grid> </Grid>
<Grid size={{ xs: 12, sm: 6 }}> <Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField <CustomTextField
fullWidth fullWidth
type='number' type='number'
label='Mobile Number' label={tBilling('mobileNumber')}
placeholder='202 555 0111' placeholder='202 555 0111'
slotProps={{ slotProps={{
input: { input: {
@@ -51,28 +55,28 @@ const Address = () => {
/> />
</Grid> </Grid>
<Grid size={{ xs: 12, sm: 6 }}> <Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField select fullWidth label='Country' value={state} onChange={e => setState(e.target.value)}> <CustomTextField select fullWidth label={tBilling('country')} value={state} onChange={e => setState(e.target.value)}>
<MenuItem value=''>Select Country</MenuItem> <MenuItem value=''>{tBilling('selectCountry')}</MenuItem>
<MenuItem value='australia'>Australia</MenuItem> <MenuItem value='australia'>{tBilling('australia')}</MenuItem>
<MenuItem value='canada'>Canada</MenuItem> <MenuItem value='canada'>{tBilling('canada')}</MenuItem>
<MenuItem value='france'>France</MenuItem> <MenuItem value='france'>{tBilling('france')}</MenuItem>
<MenuItem value='united-kingdom'>United Kingdom</MenuItem> <MenuItem value='united-kingdom'>{tBilling('unitedKingdom')}</MenuItem>
<MenuItem value='united-states'>United States</MenuItem> <MenuItem value='united-states'>{tBilling('unitedStates')}</MenuItem>
</CustomTextField> </CustomTextField>
</Grid> </Grid>
<Grid size={{ xs: 12 }}> <Grid size={{ xs: 12 }}>
<CustomTextField fullWidth label='Billing Address' variant='outlined' placeholder='Billing Address' /> <CustomTextField fullWidth label={tBilling('billingAddress')} variant='outlined' placeholder={tBilling('billingAddress')} />
</Grid> </Grid>
<Grid size={{ xs: 12, sm: 6 }}> <Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField fullWidth label='State' variant='outlined' placeholder='California' /> <CustomTextField fullWidth label={tBilling('state')} variant='outlined' placeholder='California' />
</Grid> </Grid>
<Grid size={{ xs: 12, sm: 6 }}> <Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField fullWidth type='number' label='Zip Code' variant='outlined' placeholder='231465' /> <CustomTextField fullWidth type='number' label={tBilling('zipCode')} variant='outlined' placeholder='231465' />
</Grid> </Grid>
<Grid size={{ xs: 12 }} className='flex gap-4 flex-wrap'> <Grid size={{ xs: 12 }} className='flex gap-4 flex-wrap'>
<Button variant='contained'>Save Changes</Button> <Button variant='contained'>{t('saveChanges')}</Button>
<Button variant='tonal' type='reset' color='secondary' onClick={() => setState('')}> <Button variant='tonal' type='reset' color='secondary' onClick={() => setState('')}>
Discard {tBilling('discard')}
</Button> </Button>
</Grid> </Grid>
</Grid> </Grid>
@@ -1,3 +1,7 @@
'use client'
import { useTranslations } from 'next-intl'
// MUI Imports // MUI Imports
import Card from '@mui/material/Card' import Card from '@mui/material/Card'
import CardHeader from '@mui/material/CardHeader' import CardHeader from '@mui/material/CardHeader'
@@ -21,6 +25,9 @@ import UpgradePlan from '@components/dialogs/upgrade-plan'
import OpenDialogOnElementClick from '@components/dialogs/OpenDialogOnElementClick' import OpenDialogOnElementClick from '@components/dialogs/OpenDialogOnElementClick'
const CurrentPlan = ({ data }: { data?: PricingPlanType[] }) => { const CurrentPlan = ({ data }: { data?: PricingPlanType[] }) => {
const t = useTranslations('accountSettings')
const tBilling = useTranslations('accountSettings.billing')
const buttonProps = (children: string, color: ThemeColor, variant: ButtonProps['variant']): ButtonProps => ({ const buttonProps = (children: string, color: ThemeColor, variant: ButtonProps['variant']): ButtonProps => ({
children, children,
variant, variant,
@@ -29,60 +36,60 @@ const CurrentPlan = ({ data }: { data?: PricingPlanType[] }) => {
return ( return (
<Card> <Card>
<CardHeader title='Current Plan' /> <CardHeader title={tBilling('currentPlan')} />
<CardContent> <CardContent>
<Grid container spacing={6}> <Grid container spacing={6}>
<Grid size={{ xs: 12, md: 6 }} className='flex flex-col gap-6'> <Grid size={{ xs: 12, md: 6 }} className='flex flex-col gap-6'>
<div className='flex flex-col gap-1'> <div className='flex flex-col gap-1'>
<Typography color='text.primary' className='font-medium'> <Typography color='text.primary' className='font-medium'>
Your Current Plan is Basic {tBilling('yourPlanBasic')}
</Typography> </Typography>
<Typography>A simple start for everyone</Typography> <Typography>{tBilling('simpleStart')}</Typography>
</div> </div>
<div className='flex flex-col gap-1'> <div className='flex flex-col gap-1'>
<Typography color='text.primary' className='font-medium'> <Typography color='text.primary' className='font-medium'>
Active until Dec 09, 2021 {tBilling('activeUntil', { date: 'Dec 09, 2021' })}
</Typography> </Typography>
<Typography>We will send you a notification upon Subscription expiration</Typography> <Typography>{tBilling('subscriptionExpiry')}</Typography>
</div> </div>
<div className='flex flex-col gap-1'> <div className='flex flex-col gap-1'>
<div className='flex items-center gap-1.5'> <div className='flex items-center gap-1.5'>
<Typography color='text.primary' className='font-medium'> <Typography color='text.primary' className='font-medium'>
$199 Per Month {tBilling('perMonth', { amount: '$199' })}
</Typography> </Typography>
<Chip color='primary' variant='tonal' label='Popular' size='small' /> <Chip color='primary' variant='tonal' label={tBilling('popular')} size='small' />
</div> </div>
<Typography>Standard plan for small to medium businesses</Typography> <Typography>{tBilling('standardPlan')}</Typography>
</div> </div>
</Grid> </Grid>
<Grid size={{ xs: 12, md: 6 }} className='flex flex-col gap-6'> <Grid size={{ xs: 12, md: 6 }} className='flex flex-col gap-6'>
<Alert severity='warning'> <Alert severity='warning'>
<AlertTitle>We need your attention!</AlertTitle> <AlertTitle>{tBilling('attention')}</AlertTitle>
Your plan requires update {tBilling('planRequiresUpdate')}
</Alert> </Alert>
<div className='flex flex-col gap-1'> <div className='flex flex-col gap-1'>
<div className='flex items-center justify-between'> <div className='flex items-center justify-between'>
<Typography color='text.primary' className='font-medium'> <Typography color='text.primary' className='font-medium'>
Days {tBilling('days')}
</Typography> </Typography>
<Typography color='text.primary' className='font-medium'> <Typography color='text.primary' className='font-medium'>
12 of 30 Days {tBilling('daysProgress', { current: '12', total: '30' })}
</Typography> </Typography>
</div> </div>
<LinearProgress variant='determinate' value={20} /> <LinearProgress variant='determinate' value={20} />
<Typography variant='body2'>18 days remaining until your plan requires update</Typography> <Typography variant='body2'>{tBilling('daysRemaining', { count: '18' })}</Typography>
</div> </div>
</Grid> </Grid>
<Grid size={{ xs: 12 }} className='flex gap-4 flex-wrap'> <Grid size={{ xs: 12 }} className='flex gap-4 flex-wrap'>
<OpenDialogOnElementClick <OpenDialogOnElementClick
element={Button} element={Button}
elementProps={buttonProps('Upgrade Plan', 'primary', 'contained')} elementProps={buttonProps(tBilling('upgradePlan'), 'primary', 'contained')}
dialog={UpgradePlan} dialog={UpgradePlan}
dialogProps={{ data: data }} dialogProps={{ data: data }}
/> />
<OpenDialogOnElementClick <OpenDialogOnElementClick
element={Button} element={Button}
elementProps={buttonProps('Cancel Subscription', 'error', 'tonal')} elementProps={buttonProps(tBilling('cancelSubscription'), 'error', 'tonal')}
dialog={ConfirmationDialog} dialog={ConfirmationDialog}
dialogProps={{ type: 'unsubscribe' }} dialogProps={{ type: 'unsubscribe' }}
/> />
@@ -1,5 +1,7 @@
'use client' 'use client'
import { useTranslations } from 'next-intl'
// MUI Imports // MUI Imports
import Card from '@mui/material/Card' import Card from '@mui/material/Card'
import CardHeader from '@mui/material/CardHeader' import CardHeader from '@mui/material/CardHeader'
@@ -54,14 +56,17 @@ const tableData: TableDataType[] = [
] ]
const Notifications = () => { const Notifications = () => {
const t = useTranslations('accountSettings')
const tNotif = useTranslations('accountSettings.notifications')
return ( return (
<Card> <Card>
<CardHeader <CardHeader
title='Recent Devices' title={tNotif('recentDevices')}
subheader={ subheader={
<> <>
We need permission from your browser to show notifications. {tNotif('permissionRequest')}
<Link className='text-primary'> Request Permission</Link> <Link className='text-primary'> {tNotif('requestPermission')}</Link>
</> </>
} }
/> />
@@ -70,8 +75,8 @@ const Notifications = () => {
<table className={tableStyles.table}> <table className={tableStyles.table}>
<thead> <thead>
<tr> <tr>
<th>Type</th> <th>{tNotif('type')}</th>
<th>Email</th> <th>{t('email')}</th>
<th>Browser</th> <th>Browser</th>
<th>App</th> <th>App</th>
</tr> </tr>
@@ -97,20 +102,20 @@ const Notifications = () => {
</table> </table>
</div> </div>
<CardContent> <CardContent>
<Typography className='mbe-6 font-medium'>When should we send you notifications?</Typography> <Typography className='mbe-6 font-medium'>{tNotif('whenToSend')}</Typography>
<Grid container spacing={6}> <Grid container spacing={6}>
<Grid size={{ xs: 12, sm: 6, md: 4 }}> <Grid size={{ xs: 12, sm: 6, md: 4 }}>
<CustomTextField select fullWidth defaultValue='online'> <CustomTextField select fullWidth defaultValue='online'>
<MenuItem value='online'>Only when I&#39;m online</MenuItem> <MenuItem value='online'>{tNotif('onlyWhenOnline')}</MenuItem>
<MenuItem value='anytime'>Anytime</MenuItem> <MenuItem value='anytime'>{tNotif('anytime')}</MenuItem>
</CustomTextField> </CustomTextField>
</Grid> </Grid>
<Grid size={{ xs: 12 }} className='flex gap-4 flex-wrap'> <Grid size={{ xs: 12 }} className='flex gap-4 flex-wrap'>
<Button variant='contained' type='submit'> <Button variant='contained' type='submit'>
Save Changes {t('saveChanges')}
</Button> </Button>
<Button variant='tonal' color='secondary' type='reset'> <Button variant='tonal' color='secondary' type='reset'>
Discard {tNotif('discard')}
</Button> </Button>
</Grid> </Grid>
</Grid> </Grid>
@@ -2,6 +2,7 @@
// React Imports // React Imports
import { useState } from 'react' import { useState } from 'react'
import { useTranslations } from 'next-intl'
// MUI Imports // MUI Imports
import Card from '@mui/material/Card' import Card from '@mui/material/Card'
@@ -17,6 +18,9 @@ import Button from '@mui/material/Button'
import CustomTextField from '@core/components/mui/TextField' import CustomTextField from '@core/components/mui/TextField'
const ChangePasswordCard = () => { const ChangePasswordCard = () => {
const t = useTranslations('accountSettings')
const tSecurity = useTranslations('accountSettings.security')
// States // States
const [isCurrentPasswordShown, setIsCurrentPasswordShown] = useState(false) const [isCurrentPasswordShown, setIsCurrentPasswordShown] = useState(false)
const [isConfirmPasswordShown, setIsConfirmPasswordShown] = useState(false) const [isConfirmPasswordShown, setIsConfirmPasswordShown] = useState(false)
@@ -28,14 +32,14 @@ const ChangePasswordCard = () => {
return ( return (
<Card> <Card>
<CardHeader title='Change Password' /> <CardHeader title={tSecurity('changePassword')} />
<CardContent> <CardContent>
<form> <form>
<Grid container spacing={6}> <Grid container spacing={6}>
<Grid size={{ xs: 12, sm: 6 }}> <Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField <CustomTextField
fullWidth fullWidth
label='Current Password' label={tSecurity('currentPassword')}
type={isCurrentPasswordShown ? 'text' : 'password'} type={isCurrentPasswordShown ? 'text' : 'password'}
placeholder='············' placeholder='············'
slotProps={{ slotProps={{
@@ -60,7 +64,7 @@ const ChangePasswordCard = () => {
<Grid size={{ xs: 12, sm: 6 }}> <Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField <CustomTextField
fullWidth fullWidth
label='New Password' label={tSecurity('newPassword')}
type={isNewPasswordShown ? 'text' : 'password'} type={isNewPasswordShown ? 'text' : 'password'}
placeholder='············' placeholder='············'
slotProps={{ slotProps={{
@@ -83,7 +87,7 @@ const ChangePasswordCard = () => {
<Grid size={{ xs: 12, sm: 6 }}> <Grid size={{ xs: 12, sm: 6 }}>
<CustomTextField <CustomTextField
fullWidth fullWidth
label='Confirm New Password' label={tSecurity('confirmNewPassword')}
type={isConfirmPasswordShown ? 'text' : 'password'} type={isConfirmPasswordShown ? 'text' : 'password'}
placeholder='············' placeholder='············'
slotProps={{ slotProps={{
@@ -104,26 +108,26 @@ const ChangePasswordCard = () => {
/> />
</Grid> </Grid>
<Grid size={{ xs: 12 }} className='flex flex-col gap-4'> <Grid size={{ xs: 12 }} className='flex flex-col gap-4'>
<Typography variant='h6'>Password Requirements:</Typography> <Typography variant='h6'>{tSecurity('passwordRequirements')}</Typography>
<div className='flex flex-col gap-4'> <div className='flex flex-col gap-4'>
<div className='flex items-center gap-2.5'> <div className='flex items-center gap-2.5'>
<i className='tabler-circle-filled text-[8px]' /> <i className='tabler-circle-filled text-[8px]' />
Minimum 8 characters long - the more, the better {tSecurity('passwordReq1')}
</div> </div>
<div className='flex items-center gap-2.5'> <div className='flex items-center gap-2.5'>
<i className='tabler-circle-filled text-[8px]' /> <i className='tabler-circle-filled text-[8px]' />
At least one lowercase & one uppercase character {tSecurity('passwordReq2')}
</div> </div>
<div className='flex items-center gap-2.5'> <div className='flex items-center gap-2.5'>
<i className='tabler-circle-filled text-[8px]' /> <i className='tabler-circle-filled text-[8px]' />
At least one number, symbol, or whitespace character {tSecurity('passwordReq3')}
</div> </div>
</div> </div>
</Grid> </Grid>
<Grid size={{ xs: 12 }} className='flex gap-4'> <Grid size={{ xs: 12 }} className='flex gap-4'>
<Button variant='contained'>Save Changes</Button> <Button variant='contained'>{t('saveChanges')}</Button>
<Button variant='tonal' type='reset' color='secondary'> <Button variant='tonal' type='reset' color='secondary'>
Reset {t('reset')}
</Button> </Button>
</Grid> </Grid>
</Grid> </Grid>
@@ -1,5 +1,7 @@
'use client' 'use client'
import { useTranslations } from 'next-intl'
// MUI Imports // MUI Imports
import Card from '@mui/material/Card' import Card from '@mui/material/Card'
import CardHeader from '@mui/material/CardHeader' import CardHeader from '@mui/material/CardHeader'
@@ -12,24 +14,27 @@ import MenuItem from '@mui/material/MenuItem'
import CustomTextField from '@core/components/mui/TextField' import CustomTextField from '@core/components/mui/TextField'
const CreateApiKey = () => { const CreateApiKey = () => {
const t = useTranslations('accountSettings')
const tSecurity = useTranslations('accountSettings.security')
return ( return (
<Card> <Card>
<CardHeader title='Create an API Key' /> <CardHeader title={tSecurity('createApiKey')} />
<CardContent className='!pb-0'> <CardContent className='!pb-0'>
<Grid container spacing={6}> <Grid container spacing={6}>
<Grid size={{ xs: 12, md: 6 }}> <Grid size={{ xs: 12, md: 6 }}>
<form className='flex justify-end items-end bs-full flex-col gap-5 pbe-6'> <form className='flex justify-end items-end bs-full flex-col gap-5 pbe-6'>
<CustomTextField select fullWidth label='Choose the API key type you want to create' defaultValue=''> <CustomTextField select fullWidth label={tSecurity('apiKeyType')} defaultValue=''>
<MenuItem value='full-control'>Full Control</MenuItem> <MenuItem value='full-control'>{tSecurity('fullControl')}</MenuItem>
<MenuItem value='modify'>Modify</MenuItem> <MenuItem value='modify'>{tSecurity('modify')}</MenuItem>
<MenuItem value='read-execute'>Read & Execute</MenuItem> <MenuItem value='read-execute'>{tSecurity('readExecute')}</MenuItem>
<MenuItem value='list-folder-contents'>List Folder Contents</MenuItem> <MenuItem value='list-folder-contents'>{tSecurity('listFolderContents')}</MenuItem>
<MenuItem value='read-only'>Read Only</MenuItem> <MenuItem value='read-only'>{tSecurity('readOnly')}</MenuItem>
<MenuItem value='read-write'>Read & Write</MenuItem> <MenuItem value='read-write'>{tSecurity('readWrite')}</MenuItem>
</CustomTextField> </CustomTextField>
<CustomTextField label='Name the API key' placeholder='Server key 1' fullWidth /> <CustomTextField label={tSecurity('apiKeyName')} placeholder='Server key 1' fullWidth />
<Button variant='contained' fullWidth> <Button variant='contained' fullWidth>
Create Key {tSecurity('createKey')}
</Button> </Button>
</form> </form>
</Grid> </Grid>