diff --git a/frontend/src/LandingPage/LandingPage.tsx b/frontend/src/LandingPage/LandingPage.tsx index 0a1ea49c..9c281385 100644 --- a/frontend/src/LandingPage/LandingPage.tsx +++ b/frontend/src/LandingPage/LandingPage.tsx @@ -1,10 +1,9 @@ import React from "react"; import { Link } from "react-router-dom"; -import { ArrowRight, History, Bookmark } from "lucide-react"; +import { ArrowRight, Bookmark } from "lucide-react"; import Home from "./sections/Home/Home"; import HowItWorks from "./sections/HowItWorks/HowItWorks"; import WhyNavin from "./sections/WhyNavin/WhyNavin"; -import Features from "./sections/Features/Features"; import FAQSection from "./sections/FAQSection/FAQSection"; import LogoStrip from "./sections/LogoStrip/LogoStrip"; import CoreFeatures from "./sections/CoreFeatures/CoreFeatures"; @@ -13,59 +12,15 @@ import { useReturningVisitor } from "@hooks/useReturningVisitor"; import { useAuthContext } from "@context/AuthContext"; const LandingPage: React.FC = () => { - const { isReturning, visitCount, daysSinceLastVisit } = useReturningVisitor(); + const { isReturning } = useReturningVisitor(); const { isAuthenticated } = useAuthContext(); - const showReturningBanner = isReturning && !isAuthenticated; - return (
- {/* Returning visitor banner */} - {showReturningBanner && ( -
-
-
-
- -
-
-

- Welcome back{visitCount > 1 ? ` — visit #${visitCount}` : ''}! - {daysSinceLastVisit !== null && daysSinceLastVisit > 0 && ( - - {' '}It's been {daysSinceLastVisit} {daysSinceLastVisit === 1 ? 'day' : 'days'} since your last visit. - - )} -

-
-
-
- - Sign In - - - - Get Started - -
-
-
- )} - {/* Quick-access for authenticated returning visitors */} {isReturning && isAuthenticated && (
@@ -96,9 +51,6 @@ const LandingPage: React.FC = () => {
-
- -
diff --git a/frontend/src/LandingPage/sections/CoreFeatures/CoreFeatures.test.tsx b/frontend/src/LandingPage/sections/CoreFeatures/CoreFeatures.test.tsx index 519bc1da..936b5e53 100644 --- a/frontend/src/LandingPage/sections/CoreFeatures/CoreFeatures.test.tsx +++ b/frontend/src/LandingPage/sections/CoreFeatures/CoreFeatures.test.tsx @@ -1,25 +1,7 @@ import { render, screen } from '@testing-library/react'; -import { describe, expect, it, beforeAll } from 'vitest'; +import { describe, expect, it } from 'vitest'; import CoreFeatures from './CoreFeatures'; -beforeAll(() => { - const IntersectionObserverMock = class { - observe() { } - unobserve() { } - disconnect() { } - }; - Object.defineProperty(window, 'IntersectionObserver', { - writable: true, - configurable: true, - value: IntersectionObserverMock, - }); - Object.defineProperty(globalThis, 'IntersectionObserver', { - writable: true, - configurable: true, - value: IntersectionObserverMock, - }); -}); - describe('CoreFeatures', () => { it('renders the section title and subtitle', () => { render(); @@ -31,55 +13,37 @@ describe('CoreFeatures', () => { ).toBeInTheDocument(); }); - it('renders all four feature blocks', () => { + it('renders all four feature callouts', () => { render(); - expect(screen.getByText('Track every delivery, every step of the way')).toBeInTheDocument(); - expect(screen.getByText("Don't trust. Verify.")).toBeInTheDocument(); - expect(screen.getByText('Payments that release themselves')).toBeInTheDocument(); - expect(screen.getByText('Everyone sees what they need to see')).toBeInTheDocument(); + expect(screen.getByText('Tokenized Assets')).toBeInTheDocument(); + expect(screen.getByText('IoT-Verified Milestones')).toBeInTheDocument(); + expect(screen.getByText('Smart Settlements')).toBeInTheDocument(); + expect(screen.getByText('Parity Dashboards')).toBeInTheDocument(); }); it('renders feature descriptions', () => { render(); - expect( - screen.getByText(/Navin gives you full visibility into every shipment/i) - ).toBeInTheDocument(); - expect(screen.getByText(/Hash-and-Emit architecture/i)).toBeInTheDocument(); - expect(screen.getByText(/smart contract escrow/i)).toBeInTheDocument(); - expect(screen.getByText(/four roles — Company, Carrier, Customer, and Admin/i)).toBeInTheDocument(); + expect(screen.getByText(/unique digital identity on the Stellar blockchain/i)).toBeInTheDocument(); + expect(screen.getByText(/hashed and anchored on-chain/i)).toBeInTheDocument(); + expect(screen.getByText(/released automatically via smart contract/i)).toBeInTheDocument(); + expect(screen.getByText(/single source of truth for Company, Carrier, Customer, and Admin/i)).toBeInTheDocument(); }); - it('renders bullet points for each feature', () => { + it('renders the bar-chart visualization', () => { render(); - expect(screen.getByText('Live status updates at every checkpoint')).toBeInTheDocument(); - expect(screen.getByText('IoT-powered temperature and condition monitoring')).toBeInTheDocument(); - expect(screen.getByText(/SHA-256 hashes of all shipment data/i)).toBeInTheDocument(); - expect(screen.getByText('Funds locked on shipment creation')).toBeInTheDocument(); - expect(screen.getByText(/On-chain role assignment/i)).toBeInTheDocument(); + expect( + screen.getByRole('img', { name: /illustrative visualization of on-chain shipment activity/i }) + ).toBeInTheDocument(); }); - it('renders images for each feature with proper alt text', () => { + it('renders the Track Your Shipment CTA', () => { render(); - expect(screen.getByAltText('Real-time shipment tracking visualization')).toBeInTheDocument(); - expect(screen.getByAltText('Blockchain verification data flow diagram')).toBeInTheDocument(); - expect(screen.getByAltText('Smart escrow payment flow illustration')).toBeInTheDocument(); - expect(screen.getByAltText('Role-based access control diagram')).toBeInTheDocument(); - }); - - it('applies correct layout classes for zigzag pattern', () => { - const { container } = render(); - - // Check for flex containers (no longer using .feature-block class) - const flexContainers = container.querySelectorAll('.flex.flex-col'); - expect(flexContainers.length).toBeGreaterThanOrEqual(4); - - // Verify the structure has alternating row/row-reverse layout - const parentDiv = container.querySelector('.space-y-24'); - expect(parentDiv).toBeInTheDocument(); - expect(parentDiv?.children).toHaveLength(4); + const cta = screen.getByRole('link', { name: /track your shipment/i }); + expect(cta).toBeInTheDocument(); + expect(cta).toHaveAttribute('href', '#track'); }); }); diff --git a/frontend/src/LandingPage/sections/CoreFeatures/CoreFeatures.tsx b/frontend/src/LandingPage/sections/CoreFeatures/CoreFeatures.tsx index fe528914..e6af6063 100644 --- a/frontend/src/LandingPage/sections/CoreFeatures/CoreFeatures.tsx +++ b/frontend/src/LandingPage/sections/CoreFeatures/CoreFeatures.tsx @@ -1,146 +1,120 @@ import React from "react"; +import { useTranslation } from "react-i18next"; -interface FeatureBlock { - title: string; - subtitle: string; - description: string; - bullets: string[]; - imageSrc: string; - imageAlt: string; +interface CoreFeature { + key: string; } +const CORE_FEATURES: CoreFeature[] = [ + { key: "tokenizedAssets" }, + { key: "iotMilestones" }, + { key: "smartSettlements" }, + { key: "parityDashboards" }, +]; + +const BAR_COUNT = 32; +const HIGHLIGHTED_BARS = new Set([5, 13, 21, 27]); +const INDENT_CLASSES = ["", "md:ml-8", "md:ml-16", "md:ml-24"]; + const CoreFeatures: React.FC = () => { - const features: FeatureBlock[] = [ - { - title: "Track every delivery, every step of the way", - subtitle: "Real-time Visibility", - description: "Navin gives you full visibility into every shipment milestone, from warehouse pickup to final delivery. No more guessing where your package is—everything is tracked on-chain and reflected in your dashboard.", - bullets: [ - "Live status updates at every checkpoint", - "IoT-powered temperature and condition monitoring", - "GPS tracking with real-time map visualization", - ], - imageSrc: "/images/tracking-visualization.png", - imageAlt: "Real-time shipment tracking visualization", - }, - { - title: "Don't trust. Verify.", - subtitle: "Blockchain Verification", - description: "Hash-and-Emit architecture means every milestone update is hashed and emitted as a blockchain event. You're not trusting a centralized database—you're verifying cryptographic proof.", - bullets: [ - "SHA-256 hashes of all shipment data recorded on-chain", - "Immutable audit trail accessible to all authorized parties", - "One-click Stellar Explorer link to verify transactions", - ], - imageSrc: "/images/blockchain-verification.png", - imageAlt: "Blockchain verification data flow diagram", - }, - { - title: "Payments that release themselves", - subtitle: "Smart Escrow", - description: "Navin uses smart contract escrow to hold funds until delivery is confirmed. No manual invoicing. No waiting for bank transfers. The moment a verified delivery happens, payment releases automatically.", - bullets: [ - "Funds locked on shipment creation", - "Automatic release on verified delivery", - "Built-in dispute resolution with admin override", - ], - imageSrc: "/images/smart-escrow.png", - imageAlt: "Smart escrow payment flow illustration", - }, - { - title: "Everyone sees what they need to see", - subtitle: "Role-Based Access", - description: "Navin supports four roles — Company, Carrier, Customer, and Admin. Each role sees exactly what they're authorized to see. No information asymmetry. No hidden data.", - bullets: [ - "On-chain role assignment with cryptographic proof", - "Granular permissions for shipment visibility", - "Customer and company dashboards with tailored views", - ], - imageSrc: "/images/role-access.png", - imageAlt: "Role-based access control diagram", - }, - ]; + const { t } = useTranslation("landing"); + + const bars = Array.from({ length: BAR_COUNT }, (_, i) => ({ + heightPct: 22 + (Math.sin(i * 0.55) * 0.5 + 0.5) * 68, + highlighted: HIGHLIGHTED_BARS.has(i), + })); return (
{/* Ambient glow effects */} -
-
- -
+
+
+ +
{/* Section Header */} -
+

- Core Features + {t("coreFeatures.heading")} {t("coreFeatures.headingHighlight")}

- Built on Stellar blockchain for transparency, security, and automation + {t("coreFeatures.subtitle")}

- {/* Feature Blocks with Zigzag Layout */} -
- {features.map((feature, index) => { - const isImageLeft = index % 2 === 0; - - return ( -
- {/* Image Side */} -
-
- {feature.imageAlt} - {/* Hover overlay glow */} -
-
-
+ {/* Bar-chart visualization */} +
+ {bars.map((bar, i) => ( +
+ ))} +
- {/* Content Side */} -
-

- {feature.subtitle} -

-

- {feature.title} -

-

- {feature.description} -

-
    - {feature.bullets.map((bullet, bulletIndex) => ( -
  • - - - - {bullet} -
  • - ))} -
-
+ {/* Staggered callouts with dashed connectors */} +
+ {CORE_FEATURES.map((feature, index) => ( +
+ +
+

+ {t(`coreFeatures.${feature.key}.label`)} +

+

+ {t(`coreFeatures.${feature.key}.description`)} +

- ); - })} +
+ ))} +
+ + {/* CTA */} +
diff --git a/frontend/src/LandingPage/sections/FAQSection/FAQSection.tsx b/frontend/src/LandingPage/sections/FAQSection/FAQSection.tsx index 94a2e1a1..4cd44a8a 100644 --- a/frontend/src/LandingPage/sections/FAQSection/FAQSection.tsx +++ b/frontend/src/LandingPage/sections/FAQSection/FAQSection.tsx @@ -1,45 +1,22 @@ import { useState } from "react"; import { ChevronDown } from "lucide-react"; +import { useTranslation } from "react-i18next"; type FAQItem = { - question: string; - answer: string; + key: string; }; const faqItems: FAQItem[] = [ - { - question: "What is Navin?", - answer: - "Navin is a next-generation logistics platform that combines blockchain technology with IoT tracking to provide transparent, tamper-proof shipment management. Every milestone is recorded on-chain, ensuring accountability from pickup to delivery.", - }, - { - question: "How do Stellar payments work on Navin?", - answer: - "Navin integrates with the Stellar blockchain to handle payments via smart contracts. When a shipment is confirmed, funds are held in escrow and automatically released to the logistics provider upon successful delivery—no manual processing required.", - }, - { - question: "How does IoT tracking work?", - answer: - "Our IoT sensors attached to shipments continuously report GPS location, temperature, humidity, and shock events. This data is logged in real-time and anchored to the blockchain, giving you a verifiable, tamper-proof record of your shipment's journey.", - }, - { - question: "How do I get started with Navin?", - answer: - "Simply sign up for an account, choose your role (logistics company or customer), and you'll have immediate access to the dashboard. You can create your first shipment in minutes—our onboarding tour will guide you through each step.", - }, - { - question: "Is my data secure on Navin?", - answer: - "Yes. All sensitive data is encrypted in transit and at rest. Shipment records are anchored to the Stellar blockchain, making them immutable and auditable. Access is controlled through role-based permissions, ensuring only authorized parties can view or modify shipment details.", - }, - { - question: "Which wallets are supported?", - answer: - "Navin supports any Stellar-compatible wallet, including Freighter, Lobstr, and Solar Wallet. You can connect your wallet directly from the dashboard to manage payments and view on-chain transaction history.", - }, + { key: "whatIsNavin" }, + { key: "stellarPayments" }, + { key: "iotTracking" }, + { key: "getStarted" }, + { key: "dataSecure" }, + { key: "walletsSupported" }, ]; function FAQSection() { + const { t } = useTranslation("landing"); const [openIndex, setOpenIndex] = useState(null); const handleToggle = (index: number) => { @@ -57,10 +34,10 @@ function FAQSection() { {/* Left side - FAQ Content */}

- Frequently Asked Questions + {t("faq.heading")} {t("faq.headingHighlight")}

- Everything you need to know about Navin's blockchain-powered logistics platform. + {t("faq.subtitle")}

@@ -84,7 +61,7 @@ function FAQSection() { - {item.question} + {t(`faq.${item.key}.question`)}

- {item.answer} + {t(`faq.${item.key}.answer`)}

diff --git a/frontend/src/LandingPage/sections/Features/Features.tsx b/frontend/src/LandingPage/sections/Features/Features.tsx deleted file mode 100644 index aa0b3bfc..00000000 --- a/frontend/src/LandingPage/sections/Features/Features.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import React from "react"; - -type FeatureCard = { - icon: string; - iconAlt: string; - title: string; - description: string; -}; - -const Features: React.FC = () => { - const features: FeatureCard[] = [ - { - icon: "/images/icons/tracking.svg", - iconAlt: "Real-time tracking icon", - title: "Real-time Tracking", - description: "Monitor your shipments live with precise location updates at every stage of delivery.", - }, - { - icon: "/images/icons/blockchain.svg", - iconAlt: "Immutable records icon", - title: "Immutable Records", - description: "Blockchain-powered ledger ensures every transaction is secure and tamper-proof.", - }, - { - icon: "/images/icons/settlement.svg", - iconAlt: "Automated settlements icon", - title: "Automated Settlements", - description: "Smart contracts handle payments instantly, eliminating delays and manual processing.", - }, - { - icon: "/images/icons/dashboard.svg", - iconAlt: "Responsive dashboard icon", - title: "Responsive Dashboard", - description: "Access your logistics data anywhere with our intuitive, mobile-friendly interface.", - }, - ]; - - return ( -
- {/* Ambient glow effects */} -
-
- -
-

- Key Features -

-

- Cutting-edge blockchain technology meets logistics. Experience transparency, security, and efficiency like never before. -

- -
- {features.map((feature, index) => ( -
- {/* Icon container with inset glow */} -
- {feature.iconAlt} -
- - {/* Content */} -
-

- {feature.title} -

-

- {feature.description} -

-
- - {/* Hover glow effect */} -
-
- ))} -
-
-
- ); -}; - -export default Features; diff --git a/frontend/src/LandingPage/sections/Footer/Footer.tsx b/frontend/src/LandingPage/sections/Footer/Footer.tsx index aaf64a98..116ac8b8 100644 --- a/frontend/src/LandingPage/sections/Footer/Footer.tsx +++ b/frontend/src/LandingPage/sections/Footer/Footer.tsx @@ -1,6 +1,9 @@ import { Github, Linkedin, Twitter } from "lucide-react"; +import { useTranslation } from "react-i18next"; function Footer() { + const { t } = useTranslation("landing"); + return (
{/* Background footer image */} @@ -16,17 +19,17 @@ function Footer() { {/* CTA Section */}

- Get Started Today + {t("footer.heading")} {t("footer.headingHighlight")}

- Join 500+ enterprise leaders. Get the latest on blockchain logistics and zero trust supply chain management. + {t("footer.subtitle")}

- + {/* Email Subscribe Form */}
@@ -34,7 +37,7 @@ function Footer() { type="submit" className="w-full sm:w-auto px-10 py-4 bg-primary hover:bg-primary-light text-background font-display font-semibold text-lg rounded-2xl transition-all duration-300 hover:shadow-glow-blue hover:scale-[1.02] active:scale-[0.98] border border-primary-light/40" > - Subscribe + {t("footer.subscribe")}
@@ -51,14 +54,14 @@ function Footer() { />

Navin

-

The New Standard in Logistics Security

+

{t("footer.tagline")}

{/* Social Links */}
+ + {/* Giant watermark wordmark */} + ); } diff --git a/frontend/src/LandingPage/sections/Home/Home.tsx b/frontend/src/LandingPage/sections/Home/Home.tsx index c14ab2fe..88160abf 100644 --- a/frontend/src/LandingPage/sections/Home/Home.tsx +++ b/frontend/src/LandingPage/sections/Home/Home.tsx @@ -1,6 +1,9 @@ import React from 'react'; +import { useTranslation } from 'react-i18next'; const Home: React.FC = () => { + const { t } = useTranslation('landing'); + return (
{ fontSize: 'clamp(3rem, 9vw, 7rem)', }} > - TRANSPARENT TRACKING + {t('hero.titleLine1')} {t('hero.titleLine2')}

- Our platform uses next gen tech to make your deliveries faster and more reliable. -
- Every step is visible, every shipment secure. + {t('hero.subtitle')}

@@ -67,7 +68,7 @@ const Home: React.FC = () => { href="#track" className="inline-flex items-center gap-2.5 px-8 py-3.5 sm:px-6 sm:py-3 bg-[rgba(8,40,50,0.75)] text-white text-base sm:text-[0.9rem] font-medium no-underline border-[1.5px] border-[rgba(0,180,160,0.6)] rounded-full cursor-pointer backdrop-blur-[8px] whitespace-nowrap transition-all duration-[250ms] hover:bg-[rgba(0,120,110,0.35)] hover:border-[#00d4c8] hover:shadow-[0_0_24px_rgba(0,212,200,0.3),inset_0_0_12px_rgba(0,212,200,0.08)] hover:-translate-y-0.5 focus-visible:outline-2 focus-visible:outline-[#00d4c8] focus-visible:outline-offset-4" > - Track Your Shipment + {t('hero.cta')}

- How Navin Works + {t("howItWorks.headingPrefix")} {t("howItWorks.headingHighlight")} {t("howItWorks.headingSuffix")}

- Simple, transparent, and blockchain-powered. Track your shipments from pickup to delivery. + {t("howItWorks.subtitle")}

@@ -56,10 +56,10 @@ function HowItWorks() { {/* Content */}

- {step.title} + {t(`howItWorks.${step.key}.title`)}

- {step.description} + {t(`howItWorks.${step.key}.description`)}

diff --git a/frontend/src/LandingPage/sections/LogoStrip/LogoStrip.tsx b/frontend/src/LandingPage/sections/LogoStrip/LogoStrip.tsx index 68ca7efe..0126da02 100644 --- a/frontend/src/LandingPage/sections/LogoStrip/LogoStrip.tsx +++ b/frontend/src/LandingPage/sections/LogoStrip/LogoStrip.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { useTranslation } from 'react-i18next'; const LOGOS = [ { name: 'Stellar', color: '#00D4C8' }, @@ -12,37 +13,41 @@ const LOGOS = [ const STRIP = [...LOGOS, ...LOGOS]; -const LogoStrip: React.FC = () => ( -
-

- Powered by & Trusted with -

+const LogoStrip: React.FC = () => { + const { t } = useTranslation('landing'); -
-
- {STRIP.map((logo, i) => ( -
- +

+ {t('logoStrip.poweredBy')} +

+ +
+
+ {STRIP.map((logo, i) => ( +
- {logo.name} - -
- ))} + + {logo.name} + +
+ ))} +
-
-
-); +
+ ); +}; export default LogoStrip; \ No newline at end of file diff --git a/frontend/src/LandingPage/sections/WhyNavin/WhyNavin.tsx b/frontend/src/LandingPage/sections/WhyNavin/WhyNavin.tsx index 840bf3e5..8f35ba9a 100644 --- a/frontend/src/LandingPage/sections/WhyNavin/WhyNavin.tsx +++ b/frontend/src/LandingPage/sections/WhyNavin/WhyNavin.tsx @@ -1,35 +1,34 @@ +import { useTranslation } from "react-i18next"; + type WhyNavinItem = { icon: string; iconAlt: string; - header: string; - description: string; + key: string; }; function WhyNavin() { + const { t } = useTranslation("landing"); + const whyNavin: WhyNavinItem[] = [ { icon: "/images/icons/Transparency.svg", iconAlt: "Eye icon", - header: "Total Transparency", - description: "See your shipments journey, every step of the way.", + key: "transparency", }, { icon: "/images/icons/Alerts.svg", iconAlt: "Bell icon", - header: "Real Time Alerts", - description: "Know instantly if there is a delay or issue.", + key: "alerts", }, { icon: "/images/icons/Deliveries.svg", iconAlt: "Truck icon", - header: "Safe Deliveries", - description: "Tamper proof technology prevents fraud and errors.", + key: "deliveries", }, { icon: "/images/icons/Fast.svg", iconAlt: "Rocket icon", - header: "Faster Service", - description: "Automated processes mean quicker, smoother deliveries.", + key: "fastService", }, ]; @@ -44,30 +43,30 @@ function WhyNavin() {

- Why Navin? + {t("whyNavin.heading")} {t("whyNavin.headingHighlight")}

- Blockchain-powered logistics that puts transparency, speed, and security first. + {t("whyNavin.subtitle")}

- +
{whyNavin.map((item) => (
{/* Icon container */}
{item.iconAlt}
- + {/* Content */}

- {item.header} + {t(`whyNavin.${item.key}.title`)}

- {item.description} + {t(`whyNavin.${item.key}.description`)}

diff --git a/frontend/src/components/ErrorBoundary/ErrorBoundary.tsx b/frontend/src/components/ErrorBoundary/ErrorBoundary.tsx index 2809487b..b267d480 100644 --- a/frontend/src/components/ErrorBoundary/ErrorBoundary.tsx +++ b/frontend/src/components/ErrorBoundary/ErrorBoundary.tsx @@ -34,7 +34,7 @@ class ErrorBoundary extends React.Component { if (this.state.hasError) { if (this.props.fallback) { if (typeof this.props.fallback === "function") { - return this.props.fallback(this.state.error, this.resetError); + return this.props.fallback(this.state.error ?? null, this.resetError); } return this.props.fallback; } @@ -71,6 +71,7 @@ class ErrorBoundary extends React.Component { Try Again
+
); } diff --git a/frontend/src/components/Navbar/Navbar.tsx b/frontend/src/components/Navbar/Navbar.tsx index e1eefba5..909f43c6 100644 --- a/frontend/src/components/Navbar/Navbar.tsx +++ b/frontend/src/components/Navbar/Navbar.tsx @@ -13,6 +13,34 @@ const navLinks = [ { id: "faq", key: "faq", href: "#faq" }, ]; +const LanguageSelect: React.FC<{ compact?: boolean }> = ({ compact = false }) => { + const { t, i18n } = useTranslation(["common"]); + + return ( + + ); +}; + const Navbar: React.FC = () => { const [companyLogo] = React.useState(() => { try { @@ -22,7 +50,7 @@ const Navbar: React.FC = () => { } }); const location = useLocation(); -const { t, i18n } = useTranslation(["common"]); + const { t } = useTranslation(["common"]); const isLandingPage = location.pathname === '/'; const activeSectionId = useScrollSpy( isLandingPage ? [...SECTION_IDS] : [], @@ -43,12 +71,12 @@ const { t, i18n } = useTranslation(["common"]); return (