diff --git a/ui/src/views/public/About.tsx b/ui/src/views/public/About.tsx index 66d7ad29..d4b845f8 100644 --- a/ui/src/views/public/About.tsx +++ b/ui/src/views/public/About.tsx @@ -8,14 +8,101 @@ import { import { useLocalization } from '@/utils/hooks/useLocalization' import { useCountUp } from '@/utils/hooks/useCountUp' import { Helmet } from 'react-helmet' +import { IconType } from 'react-icons' + +interface StatItem { + icon: IconType + value: string | number + labelKey: string + useCounter?: boolean + counterEnd?: number + counterSuffix?: string + counterDuration?: number +} + +interface ContentSection { + key: string + descKey: string +} + +interface AboutPageData { + stats: StatItem[] + descriptions: string[] + sections: ContentSection[] +} const About: React.FC = () => { const { translate } = useLocalization() - // Counter animations - const clientsCount = useCountUp({ end: 300, suffix: '+', duration: 2500 }) - const experienceCount = useCountUp({ end: 20, suffix: '+', duration: 2000 }) - const countriesCount = useCountUp({ end: 3, duration: 1500 }) + // About page data configuration + const aboutPageData: AboutPageData = { + stats: [ + { + icon: FaUsers, + value: 300, + labelKey: '::Public.about.stats.clients', + useCounter: true, + counterEnd: 300, + counterSuffix: '+', + counterDuration: 2500 + }, + { + icon: FaAward, + value: 20, + labelKey: '::Public.about.stats.experience', + useCounter: true, + counterEnd: 20, + counterSuffix: '+', + counterDuration: 2000 + }, + { + icon: FaClock, + value: '7/24', + labelKey: '::Public.about.stats.support', + useCounter: false + }, + { + icon: FaGlobe, + value: 3, + labelKey: '::Public.about.stats.countries', + useCounter: true, + counterEnd: 3, + counterDuration: 1500 + } + ], + descriptions: [ + '::Public.about.description.part1', + '::Public.about.description.motto', + '::Public.about.description.part2', + '::Public.about.description.closing' + ], + sections: [ + { + key: '::Public.about.mission', + descKey: '::Public.about.mission.desc' + }, + { + key: '::Public.about.vision', + descKey: '::Public.about.vision.desc' + } + ] + } + + // Counter animations based on data + const clientsCount = useCountUp({ + end: aboutPageData.stats[0].counterEnd!, + suffix: aboutPageData.stats[0].counterSuffix, + duration: aboutPageData.stats[0].counterDuration! + }) + const experienceCount = useCountUp({ + end: aboutPageData.stats[1].counterEnd!, + suffix: aboutPageData.stats[1].counterSuffix, + duration: aboutPageData.stats[1].counterDuration! + }) + const countriesCount = useCountUp({ + end: aboutPageData.stats[3].counterEnd!, + duration: aboutPageData.stats[3].counterDuration! + }) return ( <> @@ -49,32 +136,35 @@ const About: React.FC = () => {
-
- -
- {clientsCount.displayValue} -
-
{translate('::Public.about.stats.clients')}
-
-
- -
- {experienceCount.displayValue} -
-
{translate('::Public.about.stats.experience')}
-
-
- -
7/24
-
{translate('::Public.about.stats.support')}
-
-
- -
- {countriesCount.displayValue} -
-
{translate('::Public.about.stats.countries')}
-
+ {aboutPageData.stats.map((stat, index) => { + const IconComponent = stat.icon + let displayValue = stat.value + let elementRef = undefined + + // Handle counter values + if (stat.useCounter) { + if (index === 0) { + displayValue = clientsCount.displayValue + elementRef = clientsCount.elementRef + } else if (index === 1) { + displayValue = experienceCount.displayValue + elementRef = experienceCount.elementRef + } else if (index === 3) { + displayValue = countriesCount.displayValue + elementRef = countriesCount.elementRef + } + } + + return ( +
+ +
+ {displayValue} +
+
{translate(stat.labelKey)}
+
+ ) + })}
@@ -83,35 +173,31 @@ const About: React.FC = () => {
-
-

- {translate('::Public.about.description.part1')} +

+

+ {translate(aboutPageData.descriptions[0])}

-

- {translate('::Public.about.description.motto')} +

+ {translate(aboutPageData.descriptions[1])}

-

- {translate('::Public.about.description.part2')} +

+ {translate(aboutPageData.descriptions[2])}

-

- {translate('::Public.about.description.closing')} +

+ {translate(aboutPageData.descriptions[3])}

-
-

- {translate('::Public.about.mission')} -

-

{translate('::Public.about.mission.desc')}

-
-
-

- {translate('::Public.about.vision')} -

-

{translate('::Public.about.vision.desc')}

-
+ {aboutPageData.sections.map((section, index) => ( +
+

+ {translate(section.key)} +

+

{translate(section.descKey)}

+
+ ))}