diff --git a/frontend-next-migration/src/shared/assets/images/PRG_Logo.png b/frontend-next-migration/src/shared/assets/images/PRG_Logo.png
new file mode 100644
index 000000000..a706bad45
Binary files /dev/null and b/frontend-next-migration/src/shared/assets/images/PRG_Logo.png differ
diff --git a/frontend-next-migration/src/shared/i18n/locales/en/footer.json b/frontend-next-migration/src/shared/i18n/locales/en/footer.json
index 02327e170..55bacc667 100644
--- a/frontend-next-migration/src/shared/i18n/locales/en/footer.json
+++ b/frontend-next-migration/src/shared/i18n/locales/en/footer.json
@@ -3,5 +3,14 @@
"FooterPrivacy": "Privacy",
"FooterCookies": "Cookies",
"FooterConsent": "Consent",
- "FooterEthics": "Ethical guidelines"
+ "FooterEthics": "Ethical guidelines",
+ "WorkWithUs": "Apply to work with us",
+ "WhatIsPRG": "What is PRG",
+ "AltZoneHistory": "ALT Zone history",
+ "DevelopersDesigners": "Developers and designers",
+ "TermsAndPrivacy": "Terms and privacy policy",
+ "Contact": "Contact",
+ "ContactInfo": "Contact information",
+ "EmailLabel": "Email addresses",
+ "Information": "Information"
}
diff --git a/frontend-next-migration/src/shared/i18n/locales/fi/footer.json b/frontend-next-migration/src/shared/i18n/locales/fi/footer.json
index e6b25fa94..b31a29549 100644
--- a/frontend-next-migration/src/shared/i18n/locales/fi/footer.json
+++ b/frontend-next-migration/src/shared/i18n/locales/fi/footer.json
@@ -3,5 +3,14 @@
"FooterPrivacy": "Yksityisyys",
"FooterCookies": "Evästeet",
"FooterConsent": "Suostumus",
- "FooterEthics": "Eettiset ohjeet"
+ "FooterEthics": "Eettiset ohjeet",
+ "WorkWithUs": "Hae meille töihin",
+ "WhatIsPRG": "Mikä on PRG",
+ "AltZoneHistory": "ALT Zonen historia",
+ "DevelopersDesigners": "Kehittäjät ja suunnittelijat",
+ "TermsAndPrivacy": "Käyttöehdot ja tietosuoja",
+ "Contact": "Ota yhteyttä",
+ "ContactInfo": "Yhteystiedot",
+ "EmailLabel": "Sähköpostit",
+ "Information": "Tietoa"
}
diff --git a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterContact/FooterContact.module.scss b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterContact/FooterContact.module.scss
new file mode 100644
index 000000000..3cd9f6b73
--- /dev/null
+++ b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterContact/FooterContact.module.scss
@@ -0,0 +1,92 @@
+/* Contact section of the footer, containing title, email addresses and "Work with us" link. */
+
+.FooterContact {
+ display: flex;
+ flex-direction: column;
+ width: 310;
+ height: 175;
+ opacity: 1;
+ gap: 15px;
+}
+
+.Title {
+ width: 152;
+ height: 31;
+ opacity: 1;
+ font-family: DM Sans;
+ font-weight: 700;
+ font-style: Bold;
+ font-size: 24px;
+ line-height: 100%;
+ letter-spacing: 0%;
+ color: #ffa100;
+}
+
+.EmailLabel {
+ color: #faf9f6;
+ font-family: DM Sans;
+ font-weight: 400;
+ font-style: Regular;
+ font-size: 20px;
+ line-height: 100%;
+ letter-spacing: 0%;
+ text-decoration: underline;
+ text-decoration-style: solid;
+ text-decoration-thickness: 0%;
+ width: 203;
+ height: 26;
+ opacity: 1;
+}
+
+.EmailList {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ display: flex;
+ flex-direction: column;
+ gap: 0.25rem;
+ opacity: 1;
+}
+
+.Email,
+.WorkWithUsLink {
+ color: #faf9f6;
+ text-decoration: none;
+ font: var(--font-dm-s);
+ transition:
+ color 0.2s ease,
+ opacity 0.2s ease;
+
+ &:hover {
+ color: var(--footer-accent, var(--primary-color));
+ opacity: 0.8;
+ }
+
+ &:focus {
+ outline: 2px solid var(--footer-accent, var(--primary-color));
+ outline-offset: 2px;
+ }
+}
+
+.WorkWithUsLink {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.25rem;
+ font-family: DM Sans;
+ font-weight: 400;
+ font-style: Regular;
+ font-size: 20px;
+ line-height: 100%;
+ letter-spacing: 0%;
+}
+
+.Email {
+ text-decoration: underline;
+ text-underline-offset: 2px;
+}
+
+.ExternalIcon {
+ width: 0.65rem;
+ height: 0.65rem;
+ color: var(--footer-accent, var(--primary-color));
+}
diff --git a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterContact/FooterContact.tsx b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterContact/FooterContact.tsx
new file mode 100644
index 000000000..b64cc5c83
--- /dev/null
+++ b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterContact/FooterContact.tsx
@@ -0,0 +1,61 @@
+import { memo } from 'react';
+import { classNames } from '@/shared/lib/classNames/classNames';
+import { AppLink } from '@/shared/ui/AppLink/AppLink';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faExternalLink } from '@fortawesome/free-solid-svg-icons';
+import cls from './FooterContact.module.scss';
+
+/** Props for the FooterContact component, which displays contact information in the footer. */
+interface FooterContactProps {
+ className?: string;
+ title: string;
+ emailLabel?: string;
+ emails: string[];
+ workWithUsLabel?: string;
+}
+
+const DUUNITORI_JOBS_URL = 'https://duunitori.fi/tyopaikat?haku=Psyche%27s%20Royale%20Gaming';
+
+/** Component for displaying contact information in the footer.
+ * @param props - Props for the FooterContact component, including title, optional email label, list of email addresses, and an optional "Work with us" label.
+ * @returns A React component that renders the footer contact section with the provided information.
+ * @remarks This component is memoized for performance optimization, preventing unnecessary re-renders when props do not change.
+ */
+export const FooterContact = memo((props: FooterContactProps) => {
+ const { className = '', title, emailLabel, emails, workWithUsLabel } = props;
+
+ /* Render the footer contact section with a title, optional email label, list of email addresses, and a "Work with us" link. */
+ return (
+
+
{title}
+ {emailLabel &&
{emailLabel}
}
+
+ {emails.map((email, index) => (
+ -
+
+ {email}
+
+
+ ))}
+
+ {workWithUsLabel && (
+
+ {workWithUsLabel}
+
+
+ )}
+
+ );
+});
+
+FooterContact.displayName = 'FooterContact';
diff --git a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterContact/index.ts b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterContact/index.ts
new file mode 100644
index 000000000..2af983bec
--- /dev/null
+++ b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterContact/index.ts
@@ -0,0 +1 @@
+export { FooterContact } from './FooterContact';
diff --git a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterDesktop/FooterDesktop.module.scss b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterDesktop/FooterDesktop.module.scss
index 09b0b8d91..a28fb8444 100644
--- a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterDesktop/FooterDesktop.module.scss
+++ b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterDesktop/FooterDesktop.module.scss
@@ -1,57 +1,135 @@
.Footer {
- font: var(--font-dm-xl);
- background: var(--background);
+ --footer-bg: #1e3544;
+ --footer-bar-bg: #172f3d;
+ --footer-accent: #ffa100;
+ --footer-text: #faf9f6;
+ --footer-muted: #faf9f6;
+
+ font: var(--font-dm-s);
+ background: var(--footer-bg);
+ color: var(--footer-text);
display: flex;
- flex-direction: row;
- justify-content: space-evenly;
- align-items: center;
- padding: 5px 25px 5px 25px;
+ flex-direction: column;
position: relative;
z-index: 20;
+ opacity: 1;
}
-.title {
- padding-top: 1rem;
- color: var(--primary-color);
- text-align: center;
- font: var(--font-sw-xl);
+.SocialBar {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 1920px;
+ height: 100px;
+ padding-top: 20px;
+ padding-bottom: 20px;
+ gap: 22px;
+ background: var(--footer-bar-bg);
+ opacity: 1;
}
.socialSection {
- padding-top: 1rem;
+ display: flex;
+ justify-content: center;
+ width: 1920px;
+ height: 40px;
+ opacity: 1;
+}
- /* Footer controls layout now (was previously inside SocialSection component) */
+.socialSection > * {
+ width: 40px;
+ height: 40px;
+ opacity: 1;
+}
+
+.socialSection img {
+ width: 40px;
+ height: 40px;
+ opacity: 1;
+}
+
+.Inner {
display: grid;
+ grid-template-columns: 132px minmax(0, 372px);
+ align-items: start;
+ justify-content: center;
+ gap: 70px;
+ width: 100%;
+ min-height: 164px;
+ padding: 15px 24px 0;
+ opacity: 1;
+}
+
+.BrandColumn {
+ display: flex;
align-items: center;
- justify-items: center;
+ justify-content: center;
+ opacity: 1;
+}
- margin: 0 auto;
- max-width: 600px;
+.Logo {
+ width: 275;
+ height: 270;
+ opacity: 1;
+}
- grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
+.ContentGrid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 100px;
+ padding-top: 24px;
+ padding-right: 64px;
+ padding-left: 64px;
+ opacity: 1;
}
-.rights {
- padding: 1rem 0;
- text-align: center;
+.contactSection,
+.infoSection {
+ display: flex;
+ flex-direction: column;
+ opacity: 1;
}
-.FooterContainer {
- align-self: flex-start;
- justify-items: center;
+.BottomSection {
+ display: flex;
+ justify-content: center;
+ width: 100%;
+ padding-bottom: 12px;
+ opacity: 1;
}
-.ImageContainer {
- justify-items: flex-start;
+.Copyright {
+ gap: 100px;
+ margin: 2rem 0 0;
+ color: #ffffff;
+ font: var(--font-dm-s);
+ size: 16px;
+ text-align: center;
+ width: 400;
+ line-height: 100%;
+ letter-spacing: 0%;
+ opacity: 1;
}
-.FeedbackContainer {
- display: flex;
- justify-content: flex-end;
+.CopySymbol {
+ margin-right: 0.25rem;
+ opacity: 1;
}
@media (max-width: 1023px) {
- .socialSection {
- grid-template-columns: repeat(auto-fit, minmax(85px, 1fr));
+ .Inner {
+ grid-template-columns: 120px minmax(0, 1fr);
+ gap: 48px;
+ padding-inline: 32px;
+ }
+
+ .Logo {
+ width: 275;
+ height: 270;
+ opacity: 1;
}
-}
\ No newline at end of file
+
+ .ContentGrid {
+ gap: 40px;
+ }
+}
diff --git a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterDesktop/FooterDesktop.test.tsx b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterDesktop/FooterDesktop.test.tsx
index b26c34537..15137fe92 100644
--- a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterDesktop/FooterDesktop.test.tsx
+++ b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterDesktop/FooterDesktop.test.tsx
@@ -2,9 +2,16 @@ import { render, screen } from '@testing-library/react';
import { SocialIconLink, Texts } from '@/shared/types/types';
import FooterDesktop from './FooterDesktop';
-jest.mock('@/shared/ui/v2/Feedback');
+jest.mock('next/image', () => ({
+ __esModule: true,
+ default: ({ priority, alt, ...props }: any) => (
+
+ ),
+}));
-// Mock data for social links and texts
const mockSocialLinks: SocialIconLink[] = [
{ link: 'https://facebook.com', icon: '/icons/facebook.svg', name: 'Facebook' },
{ link: 'https://twitter.com', icon: '/icons/twitter.svg', name: 'Twitter' },
@@ -19,47 +26,64 @@ const mockTexts: Texts = {
companyName: 'My Company',
};
-describe('FooterDesktop', () => {
- it('renders without crashing and displays the title', () => {
- const title = 'Footer Title';
+const mockFooterLinks = {
+ workWithUsLabel: 'Apply to us',
+ whatIsPrgLabel: 'What is PRG',
+ altZoneHistoryLabel: 'ALT Zone history',
+ developersDesignersLabel: 'Developers and designers',
+ termsAndPrivacyLabel: 'Terms and privacy policy',
+};
+describe('FooterDesktop', () => {
+ it('renders the logo, contact section, and info links', () => {
render(
,
);
- // Check if the title is displayed correctly
- expect(screen.getByText(title)).toBeInTheDocument();
+ expect(screen.getByAltText('PRG Logo')).toBeInTheDocument();
+ expect(screen.getByText('Contact information')).toBeInTheDocument();
+ expect(screen.getByText('Email addresses')).toBeInTheDocument();
+ expect(screen.getByText('hello@example.com')).toBeInTheDocument();
+ expect(screen.getByText('Information')).toBeInTheDocument();
+ expect(screen.getByText('Apply to us')).toBeInTheDocument();
});
it('renders the SocialSection with correct social links', () => {
render(
,
);
- // Check if the social links are rendered
mockSocialLinks.forEach((link) => {
- expect(screen.getByAltText(link.name)).toBeInTheDocument(); // Check for images using alt text
+ expect(screen.getByAltText(link.name)).toBeInTheDocument();
});
});
- it('renders the Rights component with correct texts', () => {
+ it('renders copyright with the current company', () => {
render(
,
);
- // Check if the Rights component displays the correct year and company name
expect(
screen.getByText(`${mockTexts.currentYear} ${mockTexts.companyName}`),
).toBeInTheDocument();
diff --git a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterDesktop/FooterDesktop.tsx b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterDesktop/FooterDesktop.tsx
index 2edb38146..24a5bc23e 100644
--- a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterDesktop/FooterDesktop.tsx
+++ b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterDesktop/FooterDesktop.tsx
@@ -1,46 +1,89 @@
import { memo } from 'react';
-import { Container } from '@/shared/ui/Container';
+import Image from 'next/image';
import { SocialIconLink, Texts } from '@/shared/types/types';
-import { Rights } from '@/widgets/Footer/ui/Rights/Rights';
import { SocialSection } from '@/shared/SocialSection/SocialSection';
-import { Title } from '@/widgets/Footer/ui/Title/Title';
+import { FooterContact } from '@/shared/ui/v2/Footer/ui/FooterContact';
+import { FooterInfo } from '@/shared/ui/v2/Footer/ui/FooterInfo';
import cls from './FooterDesktop.module.scss';
import { classNames } from '@/shared/lib/classNames/classNames';
-import { FeedbackCard } from '@/shared/ui/v2/Feedback';
-import { RandomCharacter } from '@/shared/ui/v2/Footer/ui/FooterDesktop/RandomCharacter';
+import prgLogo from '@/shared/assets/images/PRG_Logo.png';
interface Props {
- title: string;
socialIconLinks: SocialIconLink[];
texts: Texts;
+ contactTitle: string;
+ contactEmailLabel?: string;
+ contactEmails: string[];
+ infoTitle: string;
+ infoLinks?: {
+ workWithUsLabel: string;
+ whatIsPrgLabel: string;
+ altZoneHistoryLabel: string;
+ developersDesignersLabel: string;
+ termsAndPrivacyLabel: string;
+ };
className?: string;
}
const FooterDesktopComponent = memo((props: Props) => {
- const { title, socialIconLinks, texts, className = '' } = props;
+ const {
+ socialIconLinks,
+ texts,
+ contactTitle,
+ contactEmailLabel,
+ contactEmails,
+ infoTitle,
+ infoLinks,
+ className = '',
+ } = props;
return (
);
});
diff --git a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterInfo/FooterInfo.module.scss b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterInfo/FooterInfo.module.scss
new file mode 100644
index 000000000..be53ffed8
--- /dev/null
+++ b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterInfo/FooterInfo.module.scss
@@ -0,0 +1,37 @@
+/* Info section of the footer, containing title and links. */
+
+.FooterInfo {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+ width: 310;
+ height: 175;
+ opacity: 1;
+ gap: 10px;
+}
+
+.Title {
+ color: #ffa100;
+ font-family: DM Sans;
+ font-weight: 700;
+ font-style: Bold;
+ font-size: 24px;
+ line-height: 100%;
+ letter-spacing: 0%;
+ width: 74;
+ height: 31;
+ opacity: 1;
+}
+
+.Links {
+ display: flex;
+ justify-content: flex-start;
+ opacity: 1;
+}
+
+@media (max-width: 767px) {
+ .Links {
+ justify-content: center;
+ text-align: center;
+ }
+}
diff --git a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterInfo/FooterInfo.tsx b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterInfo/FooterInfo.tsx
new file mode 100644
index 000000000..031bd4803
--- /dev/null
+++ b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterInfo/FooterInfo.tsx
@@ -0,0 +1,46 @@
+import { memo } from 'react';
+import { classNames } from '@/shared/lib/classNames/classNames';
+import { FooterLinks } from '@/shared/ui/v2/Footer/ui/FooterLinks';
+import cls from './FooterInfo.module.scss';
+
+/** Props for the FooterInfo component, which displays informational links in the footer. */
+interface FooterInfoProps {
+ className?: string;
+ title: string;
+ whatIsPrgLabel: string;
+ altZoneHistoryLabel: string;
+ developersDesignersLabel: string;
+ termsAndPrivacyLabel: string;
+}
+
+/** Component for displaying informational links in the footer, such as "What is PRG", "ALT Zone history", etc.
+ * @param props - Props for the FooterInfo component, including title and labels for the informational links.
+ * @returns A React component that renders the footer information section with a title and a list of informational links.
+ * @remarks This component is memoized for performance optimization, preventing unnecessary re-renders when props do not change.
+ */
+export const FooterInfo = memo((props: FooterInfoProps) => {
+ const {
+ className = '',
+ title,
+ whatIsPrgLabel,
+ altZoneHistoryLabel,
+ developersDesignersLabel,
+ termsAndPrivacyLabel,
+ } = props;
+
+ /* Render the footer info section with a title and a list of informational links. */
+ return (
+
+
{title}
+
+
+ );
+});
+
+FooterInfo.displayName = 'FooterInfo';
diff --git a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterInfo/index.ts b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterInfo/index.ts
new file mode 100644
index 000000000..afc2c7336
--- /dev/null
+++ b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterInfo/index.ts
@@ -0,0 +1 @@
+export { FooterInfo } from './FooterInfo';
diff --git a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterLinks/FooterLinks.module.scss b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterLinks/FooterLinks.module.scss
new file mode 100644
index 000000000..bff4a572b
--- /dev/null
+++ b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterLinks/FooterLinks.module.scss
@@ -0,0 +1,36 @@
+/* Links section of the footer, containing informational links such as "What is PRG", "ALT Zone history", etc. */
+
+.FooterLinks {
+ width: 100%;
+}
+
+.LinksList {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+.Link {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.375rem;
+ color: var(--footer-text, var(--white));
+ text-decoration: none;
+ font: var(--font-dm-s);
+ transition:
+ color 0.2s ease,
+ opacity 0.2s ease;
+ cursor: pointer;
+
+ &:hover {
+ color: var(--footer-accent, var(--primary-color));
+ }
+
+ &:focus {
+ outline: 2px solid var(--footer-accent, var(--primary-color));
+ outline-offset: 2px;
+ }
+}
diff --git a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterLinks/FooterLinks.tsx b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterLinks/FooterLinks.tsx
new file mode 100644
index 000000000..cab9e9a42
--- /dev/null
+++ b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterLinks/FooterLinks.tsx
@@ -0,0 +1,76 @@
+import { memo } from 'react';
+import { classNames } from '@/shared/lib/classNames/classNames';
+import { AppLink } from '@/shared/ui/AppLink/AppLink';
+import {
+ getRoutePrivacyPage,
+ getRoutePrgPage,
+ getRouteAboutPage,
+ getRouteTeamPage,
+} from '@/shared/appLinks/RoutePaths';
+import cls from './FooterLinks.module.scss';
+
+/** Props for the FooterLinks component, which displays a list of informational links in the footer. */
+interface FooterLinksProps {
+ className?: string;
+ whatIsPrgLabel: string;
+ altZoneHistoryLabel: string;
+ developersDesignersLabel: string;
+ termsAndPrivacyLabel: string;
+}
+
+/** Component for displaying informational links in the footer, such as "What is PRG", "ALT Zone history", etc.
+ * @param props - Props for the FooterLinks component, including labels for the informational links.
+ * @returns A React component that renders the footer links as a navigation list with links to different informational pages.
+ * @remarks This component is memoized for performance optimization, preventing unnecessary re-renders when props do not change.
+ */
+export const FooterLinks = memo((props: FooterLinksProps) => {
+ const {
+ className = '',
+ whatIsPrgLabel,
+ altZoneHistoryLabel,
+ developersDesignersLabel,
+ termsAndPrivacyLabel,
+ } = props;
+
+ /* Render the footer links as a navigation list with links to different informational pages. */
+ return (
+
+ );
+});
+
+FooterLinks.displayName = 'FooterLinks';
diff --git a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterLinks/index.ts b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterLinks/index.ts
new file mode 100644
index 000000000..a57b1c0e9
--- /dev/null
+++ b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterLinks/index.ts
@@ -0,0 +1 @@
+export { FooterLinks } from './FooterLinks';
diff --git a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterMobile/FooterMobile.module.scss b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterMobile/FooterMobile.module.scss
index a394cb90b..8d7e87338 100644
--- a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterMobile/FooterMobile.module.scss
+++ b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterMobile/FooterMobile.module.scss
@@ -1,33 +1,83 @@
.Footer {
- font: var(--font-dm-xl);
- background: var(--background);
+ --footer-bg: #1e3544;
+ --footer-bar-bg: #172f3d;
+ --footer-accent: #ffa100;
+ --footer-text: #faf9f6;
+ --footer-muted: #faf9f6;
+
+ font: var(--font-dm-s);
+ background: var(--footer-bg);
+ color: var(--footer-text);
display: flex;
flex-direction: column;
- gap: 2.5rem;
- padding: 1.5rem 0 1rem 0;
+ align-items: stretch;
position: relative;
z-index: 20;
}
-.title {
- color: var(--primary-color);
- font-family: var(--font-family-title);
+.SocialBar {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ min-height: 38px;
+ background: var(--footer-bar-bg);
}
.socialSection {
justify-content: center;
- padding: 2rem 0 1rem 0;
+ padding: 0;
+ display: flex;
+ gap: 13px;
+ flex-wrap: wrap;
+ margin: 0;
}
-.rights {
- text-align: center;
+.socialSection > * {
+ width: 18px;
+ height: 18px;
+}
+
+.socialSection img {
+ width: 18px;
+ height: 18px;
}
.FooterContainer {
- gap: 5rem;
+ gap: 14px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ width: 100%;
+ max-width: 222px;
+ margin: 0 auto;
+ padding: 11px 16px 9px;
+ box-sizing: border-box;
+ text-align: center;
+}
+
+.contactSection,
+.infoSection {
+ align-items: center;
+}
+
+.Copyright {
+ margin: 0;
+ color: var(--footer-muted);
+ font: var(--font-dm-xs);
}
-.FeedbackContainer {
+.CopySymbol {
+ margin-right: 0.25rem;
+}
+
+.FeedbackCard {
display: flex;
- justify-content: center;
+ flex-direction: column;
+ align-items: center;
+ gap: 8px;
+ padding: 12px 16px;
+ background: var(--footer-accent);
+ border-radius: 4px;
+ color: #fff;
+ font: var(--font-dm-s);
}
diff --git a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterMobile/FooterMobile.test.tsx b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterMobile/FooterMobile.test.tsx
index 7a3ecd6d5..cc5c642d4 100644
--- a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterMobile/FooterMobile.test.tsx
+++ b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterMobile/FooterMobile.test.tsx
@@ -1,23 +1,21 @@
import { render, screen } from '@testing-library/react';
import { SocialIconLink, Texts } from '@/shared/types/types';
import FooterMobile from './FooterMobile';
-import { beforeEach } from 'node:test';
-import { useClientTranslation } from '@/shared/i18n';
-jest.mock('@/shared/i18n', () => ({
- useClientTranslation: jest.fn(),
+jest.mock('next/image', () => ({
+ __esModule: true,
+ default: ({ priority, alt, ...props }: any) => (
+
+ ),
}));
-jest.mock('react-i18next', () => ({
- useTranslation: jest.fn().mockReturnValue({
- t: jest.fn((key) => key),
- i18n: { language: 'en', changeLanguage: jest.fn() },
- }),
+jest.mock('@/shared/ui/v2/Feedback', () => ({
+ FeedbackCard: () => FeedbackCard
,
}));
-jest.mock('@/shared/ui/v2/Feedback');
-
-// Mock data for social links and texts
const mockSocialLinks: SocialIconLink[] = [
{ link: 'https://discord.gg', icon: '/images/Discord2.svg', name: 'Discord' },
{ link: 'https://www.instagram.com', icon: '/images/Insta2.svg', name: 'Instagram' },
@@ -34,34 +32,49 @@ const mockTexts: Texts = {
companyName: 'My Company',
};
-describe('FooterMobile', () => {
- beforeEach(() => {
- (useClientTranslation as jest.Mock).mockReturnValue({ t: jest.fn((key) => key) });
- });
+const mockFooterLinks = {
+ workWithUsLabel: 'Apply to us',
+ whatIsPrgLabel: 'What is PRG',
+ altZoneHistoryLabel: 'ALT Zone history',
+ developersDesignersLabel: 'Developers and designers',
+ termsAndPrivacyLabel: 'Terms and privacy policy',
+};
- it('renders the SocialSection with correct social links', () => {
+describe('FooterMobile', () => {
+ it('renders the PRG footer content', () => {
render(
,
);
- mockSocialLinks.forEach((link) => {
- expect(screen.getByAltText(link.name)).toBeInTheDocument();
- });
+ expect(screen.getByText('Contact information')).toBeInTheDocument();
+ expect(screen.getByText('Email addresses')).toBeInTheDocument();
+ expect(screen.getByText('hello@example.com')).toBeInTheDocument();
+ expect(screen.getByText('Information')).toBeInTheDocument();
+ expect(screen.getByText('FeedbackCard')).toBeInTheDocument();
});
- it('Renders the title correctly', () => {
+ it('renders the SocialSection with correct social links', () => {
render(
,
);
- expect(screen.getByText('Testing Title')).toBeInTheDocument();
+ mockSocialLinks.forEach((link) => {
+ expect(screen.getByAltText(link.name)).toBeInTheDocument();
+ });
});
});
diff --git a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterMobile/FooterMobile.tsx b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterMobile/FooterMobile.tsx
index 9eaed0545..dc15d543d 100644
--- a/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterMobile/FooterMobile.tsx
+++ b/frontend-next-migration/src/shared/ui/v2/Footer/ui/FooterMobile/FooterMobile.tsx
@@ -1,42 +1,73 @@
import { memo } from 'react';
-import { Container } from '@/shared/ui/Container';
import { SocialIconLink, Texts } from '@/shared/types/types';
-import { Rights } from '@/widgets/Footer/ui/Rights/Rights';
import { SocialSection } from '@/shared/SocialSection/SocialSection';
-import { Title } from '@/widgets/Footer/ui/Title/Title';
+import { FooterContact } from '@/shared/ui/v2/Footer/ui/FooterContact';
+import { FooterInfo } from '@/shared/ui/v2/Footer/ui/FooterInfo';
+import { FeedbackCard } from '@/shared/ui/v2/Feedback';
import cls from './FooterMobile.module.scss';
import { classNames } from '@/shared/lib/classNames/classNames';
-import { FeedbackCard } from '@/shared/ui/v2/Feedback';
interface Props {
- title: string;
socialIconLinks: SocialIconLink[];
texts: Texts;
+ contactTitle: string;
+ contactEmailLabel?: string;
+ contactEmails: string[];
+ infoTitle: string;
+ infoLinks?: {
+ workWithUsLabel: string;
+ whatIsPrgLabel: string;
+ altZoneHistoryLabel: string;
+ developersDesignersLabel: string;
+ termsAndPrivacyLabel: string;
+ };
className?: string;
}
const FooterMobileComponent = memo((props: Props) => {
- const { title, socialIconLinks, texts, className = '' } = props;
+ const {
+ socialIconLinks,
+ texts,
+ contactTitle,
+ contactEmailLabel,
+ contactEmails,
+ infoTitle,
+ infoLinks,
+ className = '',
+ } = props;
return (