Skip to content

feat(tests): refactor test files for consistency and readability#20

Merged
hoangsonww merged 1 commit intomasterfrom
feat/enhance-landing-ui
Feb 5, 2026
Merged

feat(tests): refactor test files for consistency and readability#20
hoangsonww merged 1 commit intomasterfrom
feat/enhance-landing-ui

Conversation

@hoangsonww
Copy link
Copy Markdown
Owner

This pull request focuses on code style consistency and minor documentation improvements. The main changes include converting all test files to use double quotes instead of single quotes, ensuring uniform import and string formatting, and making small formatting tweaks in the README.md.

Code style unification:

  • All test files under __tests__/ have been updated to use double quotes for imports and strings, replacing single quotes. This applies to both JavaScript and TypeScript test files, promoting consistency throughout the codebase. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]

Documentation formatting:

  • Fixed the formatting of admonition blocks (e.g., [!IMPORTANT], [!CAUTION]) in the README.md to ensure proper rendering and readability. [1] [2]
  • Added a small formatting improvement to the GitHub Actions setup instructions in the README.md.

@hoangsonww hoangsonww self-assigned this Feb 5, 2026
Copilot AI review requested due to automatic review settings February 5, 2026 07:38
@hoangsonww hoangsonww added bug Something isn't working documentation Improvements or additions to documentation duplicate This issue or pull request already exists enhancement New feature or request help wanted Extra attention is needed good first issue Good for newcomers labels Feb 5, 2026
@vercel
Copy link
Copy Markdown

vercel Bot commented Feb 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
collabify-project-manager Building Building Preview, Comment Feb 5, 2026 7:38am

@hoangsonww hoangsonww merged commit 056dfc6 into master Feb 5, 2026
5 of 6 checks passed
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello @hoangsonww, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request primarily focuses on enhancing the user experience of the application's landing page through a complete redesign, incorporating modern UI elements and animations. Concurrently, it standardizes code style across all test files for improved maintainability and readability, and includes minor documentation formatting fixes to ensure a polished presentation.

Highlights

  • Code Style Consistency: All test files (JavaScript and TypeScript) have been refactored to consistently use double quotes for imports and string literals, replacing previous single quote usage.
  • Landing Page Redesign: The main landing page (pages/index.tsx) has undergone a significant overhaul, introducing a modern, dynamic layout with new animated components (e.g., Reveal, CountUp) and a richer content structure, including new sections for statistics, workflows, capabilities, customer stories, security, and FAQs.
  • Documentation Improvements: Minor formatting adjustments were made in README.md to ensure proper rendering of admonition blocks and improve readability in the GitHub Actions setup instructions.
  • Localization Updates: The English and Vietnamese localization files (collabify.json) have been updated with new marketing-oriented text to support the redesigned landing page content.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • README.md
    • Fixed formatting for [!IMPORTANT] and [!CAUTION] admonition blocks.
    • Added a blank line to improve readability in the GitHub Actions setup section.
  • tests/AdminPage.test.tsx
    • Converted all single quotes to double quotes for strings and imports.
  • tests/DashboardPage.test.tsx
    • Converted all single quotes to double quotes for strings and imports.
  • tests/ProfilePage.test.tsx
    • Converted all single quotes to double quotes for strings and imports.
  • tests/ProjectDetailPage.test.tsx
    • Converted all single quotes to double quotes for strings and imports.
  • tests/ProjectsPage.test.tsx
    • Converted all single quotes to double quotes for strings and imports.
  • tests/api/dashboard.test.js
    • Converted all single quotes to double quotes for strings and imports.
  • tests/api/openapi.test.js
    • Converted all single quotes to double quotes for strings and imports.
  • tests/api/projects/index.test.js
    • Converted all single quotes to double quotes for strings and imports.
  • tests/api/users/info.test.js
    • Converted all single quotes to double quotes for strings and imports.
  • tests/api/users/roles.test.js
    • Converted all single quotes to double quotes for strings and imports.
  • tests/api/users/updateProfile.test.js
    • Converted all single quotes to double quotes for strings and imports.
  • pages/index.tsx
    • Implemented a complete redesign of the landing page, introducing new sections and a modern aesthetic.
    • Added Reveal, RevealGroup, RevealItem components for scroll-triggered animations.
    • Introduced a CountUp component for animated number displays.
    • Integrated new fonts (Bebas_Neue, Sora) for improved typography.
    • Updated lucide-react imports to include new icons used in the redesigned layout.
    • Removed old FeatureCard and HowItWorksStep components as part of the redesign.
  • public/locales/en/collabify.json
    • Updated all English localization strings to align with the new content and structure of the redesigned landing page.
  • public/locales/vi/collabify.json
    • Updated all Vietnamese localization strings to align with the new content and structure of the redesigned landing page.
Activity
  • The author hoangsonww initiated this pull request.
  • The pull request includes extensive changes to the main landing page and refactoring of test files for style consistency.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a major redesign of the landing page, along with consistency improvements in test files and documentation tweaks. The new landing page is modern and feature-rich, but I've found a couple of issues to address. Specifically, the README.md admonition blocks are incorrectly formatted, which will cause rendering problems. In the new index.tsx, the dark mode is hardcoded, overriding user preferences, and the main component has become very large, which could impact maintainability. The changes to test files to enforce double quotes are a good step towards code consistency.

Comment thread README.md

> [!IMPORTANT]
> **Note**: MongoDB connection string should be in the format: `mongodb+srv://<username>:<password>@cluster.mongodb.net/<dbname>?retryWrites=true&w=majority`. Alternatively, if you are using a local MongoDB instance, it can be `mongodb://localhost:27017/collabify`.
> [!IMPORTANT] > **Note**: MongoDB connection string should be in the format: `mongodb+srv://<username>:<password>@cluster.mongodb.net/<dbname>?retryWrites=true&w=majority`. Alternatively, if you are using a local MongoDB instance, it can be `mongodb://localhost:27017/collabify`.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The new single-line format for the [!IMPORTANT] admonition block is incorrect and will not render as intended on GitHub. To ensure it displays correctly, it should be restored to the multi-line blockquote format.

Suggested change
> [!IMPORTANT] > **Note**: MongoDB connection string should be in the format: `mongodb+srv://<username>:<password>@cluster.mongodb.net/<dbname>?retryWrites=true&w=majority`. Alternatively, if you are using a local MongoDB instance, it can be `mongodb://localhost:27017/collabify`.
> [!IMPORTANT]
> **Note**: MongoDB connection string should be in the format: `mongodb+srv://<username>:<password>@cluster.mongodb.net/<dbname>?retryWrites=true&w=majority`. Alternatively, if you are using a local MongoDB instance, it can be `mongodb://localhost:27017/collabify`.

Comment thread README.md

> [!CAUTION]
> **Disclaimer:** I strongly believe that Auth0 is on its way to becoming the best authentication solution for web applications. It is a powerful tool that simplifies the authentication process and provides a wide range of features to enhance security and user experience. However, please note that this is my personal opinion, and I encourage you to evaluate different authentication solutions based on your specific needs and requirements - it does not have to be Auth0, and this project has been designed to make it easy to switch to another provider if you so choose!
> [!CAUTION] > **Disclaimer:** I strongly believe that Auth0 is on its way to becoming the best authentication solution for web applications. It is a powerful tool that simplifies the authentication process and provides a wide range of features to enhance security and user experience. However, please note that this is my personal opinion, and I encourage you to evaluate different authentication solutions based on your specific needs and requirements - it does not have to be Auth0, and this project has been designed to make it easy to switch to another provider if you so choose!
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the [!IMPORTANT] block, the [!CAUTION] admonition has been changed to a single-line format that will not render correctly. Please revert it to the proper multi-line blockquote format.

Suggested change
> [!CAUTION] > **Disclaimer:** I strongly believe that Auth0 is on its way to becoming the best authentication solution for web applications. It is a powerful tool that simplifies the authentication process and provides a wide range of features to enhance security and user experience. However, please note that this is my personal opinion, and I encourage you to evaluate different authentication solutions based on your specific needs and requirements - it does not have to be Auth0, and this project has been designed to make it easy to switch to another provider if you so choose!
> [!CAUTION]
> **Disclaimer:** I strongly believe that Auth0 is on its way to becoming the best authentication solution for web applications. It is a powerful tool that simplifies the authentication process and provides a wide range of features to enhance security and user experience. However, please note that this is my personal opinion, and I encourage you to evaluate different authentication solutions based on your specific needs and requirements - it does not have to be Auth0, and this project has been designed to make it easy to switch to another provider if you so choose!

Comment thread pages/index.tsx
);
}

function RealHome() {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The RealHome component has grown quite large (over 700 lines), which can make it difficult to maintain and understand. Consider refactoring it by breaking it down into smaller, more focused components for each section (e.g., HeroSection, StatsSection, WorkflowSection, etc.). This will improve code organization and reusability.

Comment thread pages/index.tsx
<meta name="description" content={t("metaDesc")} />
</Head>
<div
className={`${sora.className} dark relative min-h-screen overflow-hidden bg-[#0a0a0a] text-foreground`}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The dark class is hardcoded here, which forces the page into dark mode regardless of the user's system preferences. Your tailwind.config.js is configured with darkMode: "media", which is designed to respect system settings. To restore this behavior, the dark class should be removed.

Suggested change
className={`${sora.className} dark relative min-h-screen overflow-hidden bg-[#0a0a0a] text-foreground`}
className={`${sora.className} relative min-h-screen overflow-hidden bg-[#0a0a0a] text-foreground`}

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request claims to focus on "code style consistency and minor documentation improvements" by converting test files to use double quotes and fixing README formatting. However, the PR contains substantial undisclosed changes that transform the application's homepage and branding.

Changes:

  • Test files converted from single quotes to double quotes (as described)
  • Complete rewrite of the homepage component with new UI, animations, and sections
  • Complete overhaul of English and Vietnamese locale files with new enterprise-focused messaging (29→103 translation keys)
  • README.md formatting changes including broken admonition block syntax

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/api/users/updateProfile.test.js Quote style conversion (single to double)
tests/api/users/roles.test.js Quote style conversion (single to double)
tests/api/users/info.test.js Quote style conversion (single to double)
tests/api/projects/index.test.js Quote style conversion (single to double)
tests/api/openapi.test.js Quote style conversion (single to double)
tests/api/dashboard.test.js Quote style conversion (single to double)
tests/ProjectsPage.test.tsx Quote style conversion (single to double)
tests/ProjectDetailPage.test.tsx Quote style conversion (single to double)
tests/ProfilePage.test.tsx Quote style conversion (single to double)
tests/DashboardPage.test.tsx Quote style conversion (single to double)
tests/AdminPage.test.tsx Quote style conversion (single to double)
README.md Broken admonition block formatting and added blank line
pages/index.tsx UNDISCLOSED: Complete homepage rewrite with new UI, fonts, animations, and sections
public/locales/en/collabify.json UNDISCLOSED: Complete content overhaul transforming branding to enterprise focus
public/locales/vi/collabify.json UNDISCLOSED: Complete content overhaul (Vietnamese translation)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread README.md

> [!IMPORTANT]
> **Note**: MongoDB connection string should be in the format: `mongodb+srv://<username>:<password>@cluster.mongodb.net/<dbname>?retryWrites=true&w=majority`. Alternatively, if you are using a local MongoDB instance, it can be `mongodb://localhost:27017/collabify`.
> [!IMPORTANT] > **Note**: MongoDB connection string should be in the format: `mongodb+srv://<username>:<password>@cluster.mongodb.net/<dbname>?retryWrites=true&w=majority`. Alternatively, if you are using a local MongoDB instance, it can be `mongodb://localhost:27017/collabify`.
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The formatting change on this line appears to have broken the Markdown admonition block syntax. The original format had the admonition marker on a separate line from the content, which is the correct GitHub-flavored Markdown syntax:

> [!IMPORTANT]
> **Note**: ...content...

The new format combines them on one line with a > separator in the middle, which will likely not render correctly as an admonition block and may just appear as a regular blockquote.

Suggested change
> [!IMPORTANT] > **Note**: MongoDB connection string should be in the format: `mongodb+srv://<username>:<password>@cluster.mongodb.net/<dbname>?retryWrites=true&w=majority`. Alternatively, if you are using a local MongoDB instance, it can be `mongodb://localhost:27017/collabify`.
> [!IMPORTANT]
> **Note**: MongoDB connection string should be in the format: `mongodb+srv://<username>:<password>@cluster.mongodb.net/<dbname>?retryWrites=true&w=majority`. Alternatively, if you are using a local MongoDB instance, it can be `mongodb://localhost:27017/collabify`.

Copilot uses AI. Check for mistakes.
Comment thread README.md

> [!CAUTION]
> **Disclaimer:** I strongly believe that Auth0 is on its way to becoming the best authentication solution for web applications. It is a powerful tool that simplifies the authentication process and provides a wide range of features to enhance security and user experience. However, please note that this is my personal opinion, and I encourage you to evaluate different authentication solutions based on your specific needs and requirements - it does not have to be Auth0, and this project has been designed to make it easy to switch to another provider if you so choose!
> [!CAUTION] > **Disclaimer:** I strongly believe that Auth0 is on its way to becoming the best authentication solution for web applications. It is a powerful tool that simplifies the authentication process and provides a wide range of features to enhance security and user experience. However, please note that this is my personal opinion, and I encourage you to evaluate different authentication solutions based on your specific needs and requirements - it does not have to be Auth0, and this project has been designed to make it easy to switch to another provider if you so choose!
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to line 254, this admonition block formatting has been changed in a way that will likely break the rendering. The original format with the [!CAUTION] marker on a separate line from the content is the correct GitHub-flavored Markdown syntax. Combining them on one line with a > separator will prevent it from rendering as a caution admonition block.

Suggested change
> [!CAUTION] > **Disclaimer:** I strongly believe that Auth0 is on its way to becoming the best authentication solution for web applications. It is a powerful tool that simplifies the authentication process and provides a wide range of features to enhance security and user experience. However, please note that this is my personal opinion, and I encourage you to evaluate different authentication solutions based on your specific needs and requirements - it does not have to be Auth0, and this project has been designed to make it easy to switch to another provider if you so choose!
> [!CAUTION]
> **Disclaimer:** I strongly believe that Auth0 is on its way to becoming the best authentication solution for web applications. It is a powerful tool that simplifies the authentication process and provides a wide range of features to enhance security and user experience. However, please note that this is my personal opinion, and I encourage you to evaluate different authentication solutions based on your specific needs and requirements - it does not have to be Auth0, and this project has been designed to make it easy to switch to another provider if you so choose!

Copilot uses AI. Check for mistakes.
Comment thread pages/index.tsx
Comment on lines 1 to 915
import dynamic from "next/dynamic";
import Head from "next/head";
import { motion } from "framer-motion";
import Link from "next/link";
import { motion, useInView, useReducedMotion } from "framer-motion";
import {
Briefcase,
Users,
CalendarCheck,
BarChart3,
CheckCircle2,
ClipboardList,
Gauge,
Layers,
Lock,
Sliders,
BarChart,
MessagesSquare,
ShieldCheck,
Sparkles,
Target,
Workflow,
} from "lucide-react";
import { Bebas_Neue, Sora } from "next/font/google";
import { useEffect, useMemo, useRef, useState } from "react";

import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";

import { useTranslation } from "react-i18next";

function RealHome() {
const { t } = useTranslation("collabify");
const sora = Sora({
subsets: ["latin"],
weight: ["300", "400", "500", "600", "700"],
});

return (
<>
<Head>
<title>{t("title")}</title>
<meta name="description" content={t("metaDesc")} />
</Head>
<div className="relative min-h-screen bg-background text-foreground overflow-hidden flex flex-col items-center justify-center transition-colors duration-300">
<div className="relative z-10 w-full max-w-6xl px-4 py-16 flex flex-col items-center">
{/* Hero Section */}
<div className="text-center mb-12">
<motion.h1
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.2 }}
transition={{ duration: 0.4, ease: "easeOut" }}
className="text-5xl md:text-6xl font-extrabold leading-[1.2] mb-6 bg-gradient-to-r from-pink-600 via-red-600 to-yellow-400 text-transparent bg-clip-text animate-gradient"
>
{t("heroTitle")}
</motion.h1>
<motion.p
initial={{ opacity: 0, y: 10 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.2 }}
transition={{ delay: 0.15, duration: 0.4, ease: "easeOut" }}
className="text-xl max-w-2xl mx-auto"
>
{t("heroSubtitle")}
</motion.p>
</div>

{/* CTA Button */}
<div className="mb-12">
<motion.div
initial={{ opacity: 0, y: 10 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.2 }}
transition={{ delay: 0.15, duration: 0.4, ease: "easeOut" }}
>
<Link href="/api/auth/login">
<Button className="bg-primary text-primary-foreground hover:bg-primary/100 transform hover:scale-105 px-6 py-3 rounded-lg shadow-lg text-lg transition-all duration-300 cursor-pointer">
{t("getStarted")}
</Button>
</Link>
</motion.div>
</div>

{/* How It Works Section */}
<div className="w-full mb-12">
<motion.h2
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.2 }}
transition={{ duration: 0.4, ease: "easeOut" }}
className="text-2xl font-semibold mb-6 text-center"
>
{t("howItWorks")}
</motion.h2>

<div className="grid grid-cols-1 md:grid-cols-3 gap-8 items-stretch">
<HowItWorksStep
title={t("createProjects")}
text={t("createProjectsText")}
/>
<HowItWorksStep
title={t("inviteTeam")}
text={t("inviteTeamText")}
/>
<HowItWorksStep
title={t("trackProgress")}
text={t("trackProgressText")}
/>
</div>
</div>

{/* Features Section */}
<div className="w-full mb-12">
<motion.h2
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.2 }}
transition={{ duration: 0.4, ease: "easeOut" }}
className="text-2xl font-semibold mb-6 text-center"
>
{t("features")}
</motion.h2>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<FeatureCard
icon={<Briefcase className="w-8 h-8 text-primary" />}
title={t("organizeProjects")}
description={t("organizeProjectsText")}
/>
<FeatureCard
icon={<Users className="w-8 h-8 text-primary" />}
title={t("collaborate")}
description={t("collaborateText")}
/>
<FeatureCard
icon={<CalendarCheck className="w-8 h-8 text-primary" />}
title={t("stayOnTrack")}
description={t("stayOnTrackText")}
/>
<FeatureCard
icon={<Lock className="w-8 h-8 text-primary" />}
title={t("secureAuth")}
description={t("secureAuthText")}
/>
<FeatureCard
icon={<Sliders className="w-8 h-8 text-primary" />}
title={t("customWorkflows")}
description={t("customWorkflowsText")}
/>
<FeatureCard
icon={<BarChart className="w-8 h-8 text-primary" />}
title={t("analytics")}
description={t("analyticsText")}
/>
</div>
</div>

{/* Final CTA */}
<div className="mt-12 text-center">
<motion.h2
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.2 }}
transition={{ duration: 0.4, ease: "easeOut" }}
className="text-2xl font-semibold mb-4"
>
{t("finalCTA")}
</motion.h2>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.2 }}
transition={{ delay: 0.15, duration: 0.4, ease: "easeOut" }}
>
<Link href="/api/auth/login">
<Button className="bg-secondary text-secondary-foreground hover:bg-secondary/90 transform hover:scale-105 px-6 py-3 rounded-lg shadow-md text-lg transition-all duration-300 cursor-pointer">
{t("startCollabifying")}
</Button>
</Link>
</motion.div>
</div>
</div>
const bebas = Bebas_Neue({
subsets: ["latin"],
weight: ["400"],
});

{/* Global Styles for Gradient Animation */}
<style jsx global>{`
@keyframes gradient-x {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
.animate-gradient {
background-size: 200% 200%;
animation: gradient-x 4s ease infinite;
}
`}</style>
</div>
</>
);
}
const fadeUp = {
hidden: { opacity: 0, y: 24 },
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.55, ease: "easeOut" },
},
};

/** Feature Card Component with hover effect */
function FeatureCard({
icon,
title,
description,
function Reveal({
children,
className,
delay = 0,
}: {
icon: React.ReactNode;
title: string;
description: string;
children: React.ReactNode;
className?: string;
delay?: number;
}) {
const reduceMotion = useReducedMotion();

if (reduceMotion) {
return <div className={className}>{children}</div>;
}

return (
<motion.div
className={className}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.2 }}
transition={{ duration: 0.4, ease: "easeOut" }}
viewport={{ once: true, amount: 0.25 }}
transition={{ duration: 0.55, ease: "easeOut", delay }}
>
<Card className="bg-card dark:bg-card backdrop-blur-md shadow-md border border-border transition-transform duration-300 hover:-translate-y-1 hover:shadow-xl">
<CardContent className="p-6 flex flex-col items-start space-y-4">
<div className="p-3 rounded-full bg-primary/10 dark:bg-primary/20">
{icon}
</div>
<h3 className="text-lg font-semibold text-card-foreground">
{title}
</h3>
<p className="text-sm text-muted-foreground">{description}</p>
</CardContent>
</Card>
{children}
</motion.div>
);
}

/** "How It Works" Step Component with white card styling */
function HowItWorksStep({ title, text }: { title: string; text: string }) {
function RevealGroup({
children,
className,
delay = 0,
}: {
children: React.ReactNode;
className?: string;
delay?: number;
}) {
const reduceMotion = useReducedMotion();

if (reduceMotion) {
return <div className={className}>{children}</div>;
}

return (
<motion.div
className="h-full"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
className={className}
initial="hidden"
whileInView="visible"
viewport={{ once: true, amount: 0.2 }}
transition={{ duration: 0.4, ease: "easeOut" }}
variants={{
hidden: {},
visible: {
transition: { staggerChildren: 0.12, delayChildren: delay },
},
}}
>
<Card className="bg-white shadow-lg border border-gray-200 transition-transform duration-300 hover:-translate-y-1 h-full">
<CardContent className="p-6 flex flex-col items-center text-center space-y-3 h-full">
<CheckCircle2 className="w-10 h-10 text-primary mb-2" />
<h4 className="font-semibold text-lg text-gray-900">{title}</h4>
<p className="text-sm text-gray-600 flex-grow">{text}</p>
</CardContent>
</Card>
{children}
</motion.div>
);
}

function RevealItem({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) {
const reduceMotion = useReducedMotion();

if (reduceMotion) {
return <div className={className}>{children}</div>;
}

return (
<motion.div className={className} variants={fadeUp}>
{children}
</motion.div>
);
}

function CountUp({
value,
duration = 1.8,
formatter,
suffix = "",
prefix = "",
}: {
value: number;
duration?: number;
formatter?: (value: number) => string;
suffix?: string;
prefix?: string;
}) {
const ref = useRef<HTMLSpanElement | null>(null);
const reduceMotion = useReducedMotion();
const isInView = useInView(ref, { once: true, amount: 0.4 });
const [displayValue, setDisplayValue] = useState(0);

useEffect(() => {
if (!isInView) return;
if (reduceMotion) {
setDisplayValue(value);
return;
}

let frame: number;
const start = performance.now();

const animate = (now: number) => {
const elapsed = (now - start) / 1000;
const progress = Math.min(elapsed / duration, 1);
const eased = 1 - Math.pow(1 - progress, 3);
setDisplayValue(value * eased);

if (progress < 1) {
frame = requestAnimationFrame(animate);
}
};

frame = requestAnimationFrame(animate);

return () => {
if (frame) cancelAnimationFrame(frame);
};
}, [duration, isInView, reduceMotion, value]);

const formatted = formatter
? formatter(displayValue)
: displayValue.toFixed(0);

return (
<span ref={ref}>
{prefix}
{formatted}
{suffix}
</span>
);
}

function RealHome() {
const { t } = useTranslation("collabify");
const compactFormatter = useMemo(
() =>
new Intl.NumberFormat("en-US", {
notation: "compact",
maximumFractionDigits: 1,
}),
[],
);
const percentFormatter = useMemo(
() =>
new Intl.NumberFormat("en-US", {
maximumFractionDigits: 2,
}),
[],
);
const numberFormatter = useMemo(
() =>
new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
}),
[],
);

const stats = [
{
id: "tasks",
value: 2400000,
label: t("statTasks"),
formatter: (val: number) => compactFormatter.format(val),
suffix: "+",
},
{
id: "milestones",
value: 98.7,
label: t("statMilestones"),
formatter: (val: number) => percentFormatter.format(val),
suffix: "%",
},
{
id: "teams",
value: 310000,
label: t("statTeams"),
formatter: (val: number) => compactFormatter.format(val),
suffix: "+",
},
{
id: "cycle-time",
value: 42,
label: t("statCycleTime"),
formatter: (val: number) => numberFormatter.format(val),
suffix: "%",
},
{
id: "uptime",
value: 99.99,
label: t("statUptime"),
formatter: (val: number) => percentFormatter.format(val),
suffix: "%",
},
];

const heroHighlights = [
{ id: "visibility", text: t("heroHighlight1") },
{ id: "automation", text: t("heroHighlight2") },
{ id: "governance", text: t("heroHighlight3") },
];

const workflowSteps = [
{
id: "align",
title: t("workflowStep1Title"),
text: t("workflowStep1Text"),
},
{
id: "plan",
title: t("workflowStep2Title"),
text: t("workflowStep2Text"),
},
{
id: "execute",
title: t("workflowStep3Title"),
text: t("workflowStep3Text"),
},
{
id: "report",
title: t("workflowStep4Title"),
text: t("workflowStep4Text"),
},
];

const capabilities = [
{
id: "workspace",
icon: <Layers className="h-6 w-6 text-amber-600 dark:text-amber-300" />,
title: t("capability1Title"),
description: t("capability1Text"),
},
{
id: "automation",
icon: <Workflow className="h-6 w-6 text-amber-600 dark:text-amber-300" />,
title: t("capability2Title"),
description: t("capability2Text"),
},
{
id: "stakeholders",
icon: (
<MessagesSquare className="h-6 w-6 text-amber-600 dark:text-amber-300" />
),
title: t("capability3Title"),
description: t("capability3Text"),
},
{
id: "analytics",
icon: (
<BarChart3 className="h-6 w-6 text-amber-600 dark:text-amber-300" />
),
title: t("capability4Title"),
description: t("capability4Text"),
},
{
id: "goals",
icon: <Target className="h-6 w-6 text-amber-600 dark:text-amber-300" />,
title: t("capability5Title"),
description: t("capability5Text"),
},
{
id: "forecast",
icon: <Sparkles className="h-6 w-6 text-amber-600 dark:text-amber-300" />,
title: t("capability6Title"),
description: t("capability6Text"),
},
];

const stories = [
{
id: "northwind",
quote: t("story1Quote"),
name: t("story1Name"),
role: t("story1Role"),
company: t("story1Company"),
metric: t("story1MetricLabel"),
value: 36,
suffix: "%",
},
{
id: "signalforge",
quote: t("story2Quote"),
name: t("story2Name"),
role: t("story2Role"),
company: t("story2Company"),
metric: t("story2MetricLabel"),
value: 2.7,
suffix: "x",
},
{
id: "everlane",
quote: t("story3Quote"),
name: t("story3Name"),
role: t("story3Role"),
company: t("story3Company"),
metric: t("story3MetricLabel"),
value: 91,
suffix: "%",
},
];

const securityItems = [
{
id: "encryption",
icon: (
<ShieldCheck className="h-6 w-6 text-emerald-600 dark:text-emerald-300" />
),
title: t("security1Title"),
text: t("security1Text"),
},
{
id: "access",
icon: <Lock className="h-6 w-6 text-emerald-600 dark:text-emerald-300" />,
title: t("security2Title"),
text: t("security2Text"),
},
{
id: "reliability",
icon: (
<Gauge className="h-6 w-6 text-emerald-600 dark:text-emerald-300" />
),
title: t("security3Title"),
text: t("security3Text"),
},
];

const faqItems = [
{
id: "onboarding",
question: t("faq1Question"),
answer: t("faq1Answer"),
},
{
id: "reporting",
question: t("faq2Question"),
answer: t("faq2Answer"),
},
{
id: "workflows",
question: t("faq3Question"),
answer: t("faq3Answer"),
},
{
id: "security",
question: t("faq4Question"),
answer: t("faq4Answer"),
},
];

return (
<>
<Head>
<title>{t("title")}</title>
<meta name="description" content={t("metaDesc")} />
</Head>
<div
className={`${sora.className} dark relative min-h-screen overflow-hidden bg-[#0a0a0a] text-foreground`}
>
<div className="relative z-10">
<section className="mx-auto flex w-full max-w-7xl flex-col gap-12 px-6 pb-16 pt-16 sm:px-8 lg:px-12">
<div className="grid items-center gap-12 lg:grid-cols-[1.1fr_0.9fr]">
<div className="flex flex-col gap-6">
<Reveal>
<div className="inline-flex items-center gap-2 self-start rounded-full border border-border/70 bg-card/70 px-4 py-2 text-xs font-semibold uppercase tracking-[0.2em] text-muted-foreground shadow-sm dark:bg-card/60">
<span className="h-2 w-2 rounded-full bg-emerald-500" />
{t("heroBadge")}
</div>
</Reveal>
<Reveal delay={0.1}>
<h1 className="text-4xl font-semibold leading-tight text-foreground sm:text-5xl lg:text-6xl">
<span className="block text-foreground">
{t("heroTitle")}
</span>
<span className="block bg-gradient-to-r from-foreground via-emerald-500 to-amber-500 bg-clip-text text-transparent dark:via-emerald-300 dark:to-amber-300">
{t("heroHeadline")}
</span>
</h1>
</Reveal>
<Reveal delay={0.15}>
<p className="max-w-xl text-lg text-muted-foreground">
{t("heroSubtitle")}
</p>
</Reveal>
<Reveal delay={0.2}>
<div className="flex flex-col gap-4 sm:flex-row">
<Link href="/api/auth/login">
<Button className="bg-primary px-7 py-6 text-base font-semibold text-primary-foreground shadow-lg shadow-primary/20 transition-all duration-300 hover:-translate-y-0.5 hover:bg-primary/90">
{t("getStarted")}
</Button>
</Link>
<Link href="#stories">
<Button
variant="outline"
className="border-border px-7 py-6 text-base font-semibold text-foreground/80 transition-all duration-300 hover:-translate-y-0.5 hover:border-foreground/30 hover:text-foreground"
>
{t("heroSecondaryCta")}
</Button>
</Link>
</div>
</Reveal>
<RevealGroup className="grid gap-3 sm:grid-cols-2" delay={0.25}>
{heroHighlights.map((item) => (
<RevealItem key={item.id}>
<div className="flex items-start gap-3 rounded-2xl border border-border/70 bg-card/70 p-3 text-sm text-muted-foreground shadow-sm">
<CheckCircle2 className="mt-0.5 h-5 w-5 text-emerald-500" />
<span>{item.text}</span>
</div>
</RevealItem>
))}
</RevealGroup>
<Reveal delay={0.3}>
<div className="text-xs uppercase tracking-[0.2em] text-muted-foreground/70">
{t("heroNote")}
</div>
</Reveal>
</div>

<Reveal delay={0.2}>
<div className="relative rounded-[32px] border border-border bg-card/80 p-6 shadow-2xl shadow-black/10 backdrop-blur">
<div className="flex items-center justify-between">
<div>
<p className="text-xs font-semibold uppercase tracking-[0.2em] text-muted-foreground">
{t("heroCardTitle")}
</p>
<p className="text-sm text-muted-foreground/70">
{t("heroCardSubtitle")}
</p>
</div>
<div className="flex items-center gap-2 rounded-full bg-emerald-500/10 px-3 py-1 text-xs font-semibold text-emerald-600 dark:text-emerald-300">
<span className="h-2 w-2 rounded-full bg-emerald-500" />
{t("heroCardStatus")}
</div>
</div>
<div className="mt-6 grid gap-4 sm:grid-cols-2">
<div className="rounded-2xl bg-slate-900 p-5 text-white dark:bg-slate-950">
<div
className={`${bebas.className} text-4xl tracking-wide`}
>
<CountUp
value={98.7}
formatter={(val) => percentFormatter.format(val)}
suffix="%"
/>
</div>
<p className="mt-2 text-xs uppercase tracking-[0.2em] text-white/70">
{t("heroCardMetric1")}
</p>
</div>
<div className="rounded-2xl border border-border bg-card p-5">
<div
className={`${bebas.className} text-4xl tracking-wide text-foreground`}
>
<CountUp
value={1.2}
formatter={(val) => percentFormatter.format(val)}
suffix="M"
/>
</div>
<p className="mt-2 text-xs uppercase tracking-[0.2em] text-muted-foreground">
{t("heroCardMetric2")}
</p>
</div>
</div>
<div className="mt-4 rounded-2xl border border-border bg-card p-5">
<div className="flex items-center justify-between text-sm font-semibold text-muted-foreground">
<span>{t("heroCardMetric3")}</span>
<span className="text-foreground">72%</span>
</div>
<div className="mt-3 h-2 rounded-full bg-muted">
<motion.div
className="h-2 rounded-full bg-gradient-to-r from-emerald-400 to-emerald-600"
initial={{ width: 0 }}
whileInView={{ width: "72%" }}
viewport={{ once: true, amount: 0.6 }}
transition={{ duration: 1, ease: "easeOut" }}
/>
</div>
<p className="mt-2 text-xs text-muted-foreground/70">
{t("heroCardFootnote")}
</p>
</div>
</div>
</Reveal>
</div>

<Reveal delay={0.15}>
<div className="flex flex-wrap items-center gap-4 rounded-2xl border border-border bg-card/70 px-6 py-4 text-sm text-muted-foreground shadow-sm">
<span className="font-semibold text-foreground">
{t("trustedBy")}
</span>
<RevealGroup className="flex flex-wrap items-center gap-3">
{[
"Northwind",
"Apex",
"SignalForge",
"Everlane",
"Maven",
"Boreal",
].map((brand) => (
<RevealItem key={brand}>
<span className="rounded-full border border-border bg-card px-3 py-1 text-xs font-semibold uppercase tracking-[0.2em] text-muted-foreground/80">
{brand}
</span>
</RevealItem>
))}
</RevealGroup>
</div>
</Reveal>
</section>

<section className="mx-auto w-full max-w-7xl px-6 pb-16 sm:px-8 lg:px-12">
<Reveal>
<div className="text-center">
<p className="text-xs font-semibold uppercase tracking-[0.3em] text-amber-600 dark:text-amber-300">
{t("statsTitle")}
</p>
<h2 className="mt-3 text-3xl font-semibold text-foreground sm:text-4xl">
{t("statsSubtitle")}
</h2>
<p className="mt-3 text-sm text-muted-foreground">
{t("statsNote")}
</p>
</div>
</Reveal>
<RevealGroup className="mt-10 grid gap-4 sm:grid-cols-2 lg:grid-cols-5">
{stats.map((stat) => (
<RevealItem key={stat.id}>
<Card className="h-full border-border bg-card/90 shadow-lg shadow-black/5">
<CardContent className="flex h-full flex-col justify-between gap-4 p-6">
<div
className={`${bebas.className} text-4xl tracking-wide text-foreground sm:text-5xl`}
>
<CountUp
value={stat.value}
formatter={stat.formatter}
suffix={stat.suffix}
/>
</div>
<p className="text-sm text-muted-foreground">
{stat.label}
</p>
</CardContent>
</Card>
</RevealItem>
))}
</RevealGroup>
</section>

<section
id="workflow"
className="mx-auto w-full max-w-7xl px-6 pb-16 sm:px-8 lg:px-12"
>
<Reveal>
<div className="flex flex-col gap-3 text-center">
<p className="text-xs font-semibold uppercase tracking-[0.3em] text-teal-600 dark:text-teal-300">
{t("workflowTitle")}
</p>
<h2 className="text-3xl font-semibold text-foreground sm:text-4xl">
{t("workflowSubtitle")}
</h2>
</div>
</Reveal>
<RevealGroup className="mt-10 grid gap-6 md:grid-cols-2">
{workflowSteps.map((step, index) => (
<RevealItem key={step.id}>
<Card className="h-full border-border bg-card/90 shadow-lg shadow-black/5">
<CardContent className="flex h-full flex-col gap-4 p-6">
<div className="flex items-center gap-3">
<span className="flex h-10 w-10 items-center justify-center rounded-full bg-amber-100 text-sm font-semibold text-amber-700 dark:bg-amber-500/20 dark:text-amber-200">
0{index + 1}
</span>
<h3 className="text-lg font-semibold text-foreground">
{step.title}
</h3>
</div>
<p className="text-sm text-muted-foreground">
{step.text}
</p>
</CardContent>
</Card>
</RevealItem>
))}
</RevealGroup>
</section>

<section className="mx-auto w-full max-w-7xl px-6 pb-16 sm:px-8 lg:px-12">
<div className="grid gap-10 lg:grid-cols-[1.05fr_0.95fr]">
<div>
<Reveal>
<p className="text-xs font-semibold uppercase tracking-[0.3em] text-muted-foreground">
{t("capabilitiesTitle")}
</p>
</Reveal>
<Reveal delay={0.05}>
<h2 className="mt-3 text-3xl font-semibold text-foreground sm:text-4xl">
{t("capabilitiesSubtitle")}
</h2>
</Reveal>
<RevealGroup className="mt-6 grid gap-4 sm:grid-cols-2">
{capabilities.map((capability) => (
<RevealItem key={capability.id}>
<Card className="h-full border-border bg-card/90 shadow-lg shadow-black/5">
<CardContent className="flex h-full flex-col gap-3 p-5">
<div className="flex h-12 w-12 items-center justify-center rounded-2xl bg-amber-50 dark:bg-amber-500/10">
{capability.icon}
</div>
<h3 className="text-base font-semibold text-foreground">
{capability.title}
</h3>
<p className="text-sm text-muted-foreground">
{capability.description}
</p>
</CardContent>
</Card>
</RevealItem>
))}
</RevealGroup>
</div>
<RevealGroup className="flex flex-col gap-6">
<RevealItem>
<Card className="border-border bg-slate-900 text-white shadow-xl shadow-black/10 dark:bg-slate-950">
<CardContent className="flex flex-col gap-6 p-6">
<div className="flex items-center justify-between">
<div>
<p className="text-xs font-semibold uppercase tracking-[0.2em] text-white/70">
{t("commandTitle")}
</p>
<h3 className="mt-2 text-2xl font-semibold text-white">
{t("commandSubtitle")}
</h3>
</div>
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-white/10">
<ClipboardList className="h-6 w-6 text-white" />
</div>
</div>
<div className="grid gap-3">
{[
t("commandBullet1"),
t("commandBullet2"),
t("commandBullet3"),
t("commandBullet4"),
].map((bullet) => (
<div
key={bullet}
className="flex items-start gap-3 rounded-2xl border border-white/10 bg-white/5 px-4 py-3 text-sm text-white/80"
>
<CheckCircle2 className="mt-0.5 h-5 w-5 text-emerald-400" />
<span>{bullet}</span>
</div>
))}
</div>
</CardContent>
</Card>
</RevealItem>
<RevealItem>
<Card className="border-border bg-card/90 shadow-lg shadow-black/5">
<CardContent className="grid gap-4 p-6">
<div>
<p className="text-xs font-semibold uppercase tracking-[0.2em] text-muted-foreground/80">
{t("commandMetricTitle")}
</p>
<h3 className="mt-2 text-lg font-semibold text-foreground">
{t("commandMetricSubtitle")}
</h3>
</div>
<div className="grid gap-4 sm:grid-cols-3">
{[
{
value: 18,
label: t("commandMetricValue1Label"),
suffix: "%",
},
{
value: 22,
label: t("commandMetricValue2Label"),
suffix: "%",
},
{
value: 3.4,
label: t("commandMetricValue3Label"),
suffix: "x",
},
].map((metric) => (
<div
key={metric.label}
className="rounded-2xl border border-border bg-muted/50 px-4 py-4"
>
<div
className={`${bebas.className} text-3xl text-foreground`}
>
<CountUp
value={metric.value}
formatter={(val) =>
percentFormatter.format(val)
}
suffix={metric.suffix}
/>
</div>
<p className="mt-2 text-xs text-muted-foreground">
{metric.label}
</p>
</div>
))}
</div>
</CardContent>
</Card>
</RevealItem>
</RevealGroup>
</div>
</section>

<section
id="stories"
className="mx-auto w-full max-w-7xl px-6 pb-16 sm:px-8 lg:px-12"
>
<Reveal>
<div className="flex flex-col gap-3">
<p className="text-xs font-semibold uppercase tracking-[0.3em] text-amber-600 dark:text-amber-300">
{t("storiesTitle")}
</p>
<h2 className="text-3xl font-semibold text-foreground sm:text-4xl">
{t("storiesSubtitle")}
</h2>
</div>
</Reveal>
<Reveal>
<div className="mt-8 overflow-x-auto overflow-y-visible">
<RevealGroup className="flex min-w-full gap-6 px-2 py-6 sm:px-4">
{stories.map((story) => (
<RevealItem key={story.id}>
<Card className="min-w-[280px] flex-1 border-border bg-card/90 shadow-lg shadow-black/5 transition-transform duration-300 hover:-translate-y-1 lg:min-w-[320px]">
<CardContent className="flex h-full flex-col gap-4 p-6">
<p className="text-sm text-muted-foreground">
“{story.quote}”
</p>
<div className="mt-auto flex items-center justify-between">
<div>
<p className="text-sm font-semibold text-foreground">
{story.name}
</p>
<p className="text-xs text-muted-foreground">
{story.role} · {story.company}
</p>
</div>
<div className="rounded-xl border border-amber-200/70 bg-amber-50 px-3 py-2 text-center dark:border-amber-500/40 dark:bg-amber-500/10">
<div
className={`${bebas.className} text-2xl text-amber-700 dark:text-amber-200`}
>
<CountUp
value={story.value}
formatter={(val) =>
percentFormatter.format(val)
}
suffix={story.suffix}
/>
</div>
<p className="text-[10px] uppercase tracking-[0.2em] text-amber-600 dark:text-amber-300">
{story.metric}
</p>
</div>
</div>
</CardContent>
</Card>
</RevealItem>
))}
</RevealGroup>
</div>
</Reveal>
</section>

<section className="mx-auto w-full max-w-7xl px-6 pb-16 sm:px-8 lg:px-12">
<Reveal>
<div className="flex flex-col gap-3 text-center">
<p className="text-xs font-semibold uppercase tracking-[0.3em] text-emerald-600 dark:text-emerald-300">
{t("securityTitle")}
</p>
<h2 className="text-3xl font-semibold text-foreground sm:text-4xl">
{t("securitySubtitle")}
</h2>
</div>
</Reveal>
<RevealGroup className="mt-10 grid gap-6 md:grid-cols-3">
{securityItems.map((item) => (
<RevealItem key={item.id}>
<Card className="h-full border-border bg-card/90 shadow-lg shadow-black/5">
<CardContent className="flex h-full flex-col gap-4 p-6">
<div className="flex h-12 w-12 items-center justify-center rounded-2xl bg-emerald-50 dark:bg-emerald-500/10">
{item.icon}
</div>
<h3 className="text-lg font-semibold text-foreground">
{item.title}
</h3>
<p className="text-sm text-muted-foreground">
{item.text}
</p>
</CardContent>
</Card>
</RevealItem>
))}
</RevealGroup>
</section>

<section className="mx-auto w-full max-w-7xl px-6 pb-16 sm:px-8 lg:px-12">
<Reveal>
<div className="flex flex-col gap-3 text-center">
<p className="text-xs font-semibold uppercase tracking-[0.3em] text-muted-foreground">
{t("faqTitle")}
</p>
<h2 className="text-3xl font-semibold text-foreground sm:text-4xl">
{t("faqSubtitle")}
</h2>
</div>
</Reveal>
<RevealGroup className="mt-10 grid gap-6 lg:grid-cols-2">
{faqItems.map((item) => (
<RevealItem key={item.id}>
<Card className="h-full border-border bg-card/90 shadow-lg shadow-black/5">
<CardContent className="flex h-full flex-col gap-3 p-6">
<h3 className="text-base font-semibold text-foreground">
{item.question}
</h3>
<p className="text-sm text-muted-foreground">
{item.answer}
</p>
</CardContent>
</Card>
</RevealItem>
))}
</RevealGroup>
</section>

<section className="mx-auto w-full max-w-7xl px-6 pb-20 sm:px-8 lg:px-12">
<Reveal>
<div className="rounded-[32px] border border-border bg-slate-900 px-8 py-12 text-center text-white shadow-2xl shadow-black/20 dark:bg-slate-950">
<p className="text-xs font-semibold uppercase tracking-[0.3em] text-emerald-300 dark:text-emerald-200">
{t("finalCTA")}
</p>
<h2 className="mt-3 text-3xl font-semibold sm:text-4xl">
{t("finalCTASubtitle")}
</h2>
<div className="mt-6 flex flex-col justify-center gap-4 sm:flex-row">
<Link href="/api/auth/login">
<Button className="bg-white px-7 py-6 text-base font-semibold text-slate-900 shadow-lg shadow-black/10 transition-all duration-300 hover:-translate-y-0.5 hover:bg-slate-100 dark:bg-white/10 dark:text-white dark:hover:bg-white/20">
{t("startCollabifying")}
</Button>
</Link>
<Link href="#workflow">
<Button
variant="outline"
className="border-white/40 px-7 py-6 text-base font-semibold text-white transition-all duration-300 hover:-translate-y-0.5 hover:bg-white/10 dark:border-white/30 dark:hover:bg-white/15"
>
{t("heroSecondaryCta")}
</Button>
</Link>
</div>
</div>
</Reveal>
</section>
</div>
</div>
</>
);
}
const Home = dynamic(() => Promise.resolve(RealHome), { ssr: false });
export { Home as default };
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR description states it focuses on "code style consistency and minor documentation improvements" by converting test files to use double quotes and fixing README formatting. However, this file contains a complete rewrite of the homepage component with substantial functional changes including:

  1. Complete UI redesign with new sections (workflow, capabilities, stories, security, FAQ)
  2. New dependencies (Bebas_Neue, Sora fonts)
  3. New animation components (Reveal, RevealGroup, RevealItem, CountUp)
  4. Extensive new data structures and content

These are major application changes that should be clearly documented in the PR description, not omitted. This discrepancy between the PR description and actual changes makes it difficult to properly review the intent and impact of these modifications.

Copilot uses AI. Check for mistakes.
Comment on lines 1 to 103
{
"title": "Collabify | Your Project Management Solution",
"metaDesc": "Manage system-wide settings, user roles, and view system logs with Collabify.",
"title": "Collabify | Enterprise Project Intelligence",
"metaDesc": "Collabify unifies planning, execution, and reporting so teams deliver faster with full visibility, analytics, and secure collaboration.",
"heroBadge": "Enterprise-grade Project Operations",
"heroTitle": "Collabify",
"heroSubtitle": "The ultimate platform to seamlessly plan, organize, and collaborate on projects with your team – all in one place.",
"heroHeadline": "Precision project intelligence for modern teams.",
"heroSubtitle": "Unify strategy, execution, and reporting across every portfolio with real-time visibility, automation, and secure collaboration.",
"getStarted": "Get Started",
"howItWorks": "How Collabify Works",
"createProjects": "Create Projects",
"createProjectsText": "Set up new projects instantly and define tasks or milestones.",
"inviteTeam": "Invite Your Team",
"inviteTeamText": "Add collaborators, assign roles, and keep everyone aligned.",
"trackProgress": "Track Progress",
"trackProgressText": "Use real-time dashboards, charts, and tasks to ensure on-time delivery.",
"features": "Features",
"organizeProjects": "Organize Projects",
"organizeProjectsText": "Manage multiple projects seamlessly with clear task assignments.",
"collaborate": "Collaborate",
"collaborateText": "Invite team members, discuss tasks, and keep everyone in sync.",
"stayOnTrack": "Stay on Track",
"stayOnTrackText": "Monitor deadlines with built-in charts and real-time updates.",
"secureAuth": "Secure Authentication",
"secureAuthText": "Leverage Auth0 for secure, seamless, and reliable user authentication.",
"customWorkflows": "Customizable Workflows",
"customWorkflowsText": "Tailor workflows to suit your team’s unique project management needs.",
"analytics": "Analytics & Insights",
"analyticsText": "Gain actionable insights through real-time analytics and reporting.",
"finalCTA": "Ready to transform your team’s productivity?",
"startCollabifying": "Start Collabifying!"
"heroSecondaryCta": "View the Playbook",
"heroHighlight1": "Portfolio-wide visibility across every initiative and owner.",
"heroHighlight2": "Automated risk signals, dependencies, and status rollups.",
"heroHighlight3": "Audit-ready security with granular access controls.",
"heroNote": "SOC 2-ready • 24/7 support • Global data residency",
"heroCardTitle": "Command Center",
"heroCardSubtitle": "Live portfolio health",
"heroCardStatus": "All systems go",
"heroCardMetric1": "On-time delivery",
"heroCardMetric2": "Active workstreams",
"heroCardMetric3": "Capacity in balance",
"heroCardFootnote": "Signals refresh every 5 minutes",
"trustedBy": "Trusted by high-velocity teams",
"statsTitle": "Performance signals",
"statsSubtitle": "Big numbers that show momentum.",
"statsNote": "Aggregated from active customers over the past 12 months.",
"statTasks": "Tasks coordinated",
"statMilestones": "Milestones achieved on time",
"statTeams": "Teams onboarded",
"statCycleTime": "Cycle time reduction",
"statUptime": "Platform uptime",
"workflowTitle": "How it flows",
"workflowSubtitle": "From kickoff to closeout, every detail aligned.",
"workflowStep1Title": "Align the portfolio",
"workflowStep1Text": "Capture objectives, budgets, and ownership across every program.",
"workflowStep2Title": "Build the plan",
"workflowStep2Text": "Create roadmaps, dependencies, and staffing plans in minutes.",
"workflowStep3Title": "Execute with clarity",
"workflowStep3Text": "Automate status, risk flags, and stakeholder updates.",
"workflowStep4Title": "Report with confidence",
"workflowStep4Text": "Deliver board-ready insights with live metrics and narrative.",
"capabilitiesTitle": "Capabilities",
"capabilitiesSubtitle": "Everything you need to run a high-precision PMO.",
"capability1Title": "Unified workspaces",
"capability1Text": "One surface for roadmaps, tasks, files, and approvals.",
"capability2Title": "Workflow automation",
"capability2Text": "Standardize delivery and eliminate manual status chasing.",
"capability3Title": "Stakeholder hub",
"capability3Text": "Centralize communication, decisions, and accountability.",
"capability4Title": "Live analytics",
"capability4Text": "Track velocity, cost, and outcome impact in real time.",
"capability5Title": "Goal alignment",
"capability5Text": "Tie every initiative to outcomes and strategic themes.",
"capability6Title": "Portfolio forecasting",
"capability6Text": "Model scenarios and forecast delivery confidence.",
"commandTitle": "Portfolio command",
"commandSubtitle": "Orchestrate every moving part.",
"commandBullet1": "Multi-project dashboards with drilldowns.",
"commandBullet2": "Automated alerts for schedule or budget drift.",
"commandBullet3": "Executive-ready briefings in seconds.",
"commandBullet4": "Role-based views for every stakeholder.",
"commandMetricTitle": "Recent impact",
"commandMetricSubtitle": "Quarter-over-quarter gains across delivery.",
"commandMetricValue1Label": "Faster cycle time",
"commandMetricValue2Label": "Fewer escalations",
"commandMetricValue3Label": "More capacity unlocked",
"storiesTitle": "Customer outcomes",
"storiesSubtitle": "Real teams. Real improvements.",
"story1Quote": "We consolidated 12 portfolios into one view and finally hit our deadlines.",
"story1Name": "Avery Park",
"story1Role": "VP, Program Management",
"story1Company": "Northwind",
"story1MetricLabel": "On-time delivery",
"story2Quote": "Collabify replaced five tools and gave our execs a single source of truth.",
"story2Name": "Nina Holt",
"story2Role": "Director of Operations",
"story2Company": "SignalForge",
"story2MetricLabel": "Decision velocity",
"story3Quote": "Our PMO gained confidence by seeing risks before they hit production.",
"story3Name": "Mateo Ruiz",
"story3Role": "Head of PMO",
"story3Company": "Everlane",
"story3MetricLabel": "Risk reduction",
"securityTitle": "Security & compliance",
"securitySubtitle": "Enterprise safeguards without slowing you down.",
"security1Title": "Data encryption",
"security1Text": "AES-256 at rest and TLS 1.2+ in transit across all environments.",
"security2Title": "Access governance",
"security2Text": "Granular roles, SSO, and audit logs for regulated teams.",
"security3Title": "Reliability",
"security3Text": "Global infrastructure with multi-region redundancy.",
"faqTitle": "FAQ",
"faqSubtitle": "Answers for teams evaluating Collabify.",
"faq1Question": "How fast can we onboard a portfolio?",
"faq1Answer": "Most teams launch within two weeks using templates and guided migration.",
"faq2Question": "Does Collabify support multi-entity reporting?",
"faq2Answer": "Yes. Roll up programs by business unit, region, or strategic theme.",
"faq3Question": "Can we customize workflows and approvals?",
"faq3Answer": "Absolutely. Configure stages, rules, and notifications per team.",
"faq4Question": "What security standards do you support?",
"faq4Answer": "We align to SOC 2 and GDPR requirements with optional data residency.",
"finalCTA": "Ready to transform delivery?",
"finalCTASubtitle": "Bring your entire portfolio into focus with Collabify.",
"startCollabifying": "Start Collabifying"
}
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR description claims to only make "code style consistency and minor documentation improvements," but this locale file has been completely rewritten with entirely new content. The changes include:

  1. Complete replacement of all translation keys and values
  2. Addition of 74 new translation keys (from 29 to 103)
  3. Transformation from a simple project management tool description to an enterprise-focused project intelligence platform

This is a substantial content change that affects the application's messaging and branding, not a minor documentation improvement. This should be clearly documented in the PR description.

Copilot uses AI. Check for mistakes.
Comment on lines 1 to 103
{
"title": "Collabify | Giải pháp Quản lý Dự án của Bạn",
"metaDesc": "Quản lý cài đặt hệ thống, vai trò người dùng và xem nhật ký hệ thống với Collabify.",
"title": "Collabify | Nền tảng điều hành dự án doanh nghiệp",
"metaDesc": "Collabify hợp nhất lập kế hoạch, thực thi và báo cáo để đội ngũ giao hàng nhanh hơn với minh bạch thời gian thực, tự động hóa và cộng tác an toàn.",
"heroBadge": "Vận hành dự án cấp doanh nghiệp",
"heroTitle": "Collabify",
"heroSubtitle": "Nền tảng tối ưu để lập kế hoạch, tổ chức và cộng tác trên dự án với đội ngũ của bạn – tất cả trong một.",
"heroHeadline": "Trí tuệ dự án chính xác cho đội ngũ hiện đại.",
"heroSubtitle": "Kết nối chiến lược, thực thi và báo cáo trên toàn bộ danh mục với khả năng quan sát thời gian thực, tự động hóa và cộng tác an toàn.",
"getStarted": "Bắt đầu",
"howItWorks": "Cách Collabify Hoạt Động",
"createProjects": "Tạo Dự Án",
"createProjectsText": "Thiết lập dự án mới ngay lập tức và xác định các nhiệm vụ hoặc cột mốc.",
"inviteTeam": "Mời Đội Ngũ",
"inviteTeamText": "Thêm cộng tác viên, gán vai trò, và giữ cho mọi người luôn đồng bộ.",
"trackProgress": "Theo Dõi Tiến Độ",
"trackProgressText": "Sử dụng bảng điều khiển, biểu đồ và nhiệm vụ thời gian thực để đảm bảo hoàn thành đúng hạn.",
"features": "Tính Năng",
"organizeProjects": "Quản Lý Dự Án",
"organizeProjectsText": "Quản lý nhiều dự án liền mạch với nhiệm vụ được phân công rõ ràng.",
"collaborate": "Cộng Tác",
"collaborateText": "Mời thành viên, thảo luận nhiệm vụ và luôn giữ mọi người trong tầm kiểm soát.",
"stayOnTrack": "Giữ Tiến Độ",
"stayOnTrackText": "Giám sát hạn chót với biểu đồ tích hợp và cập nhật theo thời gian thực.",
"secureAuth": "Xác Thực An Toàn",
"secureAuthText": "Tích hợp Auth0 để xác thực người dùng an toàn và đáng tin cậy.",
"customWorkflows": "Quy Trình Tùy Chỉnh",
"customWorkflowsText": "Tùy chỉnh quy trình làm việc phù hợp với nhu cầu quản lý dự án riêng.",
"analytics": "Phân Tích & Thông Tin",
"analyticsText": "Nhận thông tin hữu ích qua phân tích và báo cáo theo thời gian thực.",
"finalCTA": "Sẵn sàng nâng tầm năng suất cho đội ngũ của bạn?",
"startCollabifying": "Bắt đầu với Collabify!"
"heroSecondaryCta": "Xem lộ trình",
"heroHighlight1": "Tầm nhìn danh mục toàn diện cho mọi sáng kiến và chủ sở hữu.",
"heroHighlight2": "Tự động phát hiện rủi ro, phụ thuộc và tổng hợp trạng thái.",
"heroHighlight3": "Bảo mật sẵn sàng kiểm toán với phân quyền chi tiết.",
"heroNote": "Sẵn sàng SOC 2 • Hỗ trợ 24/7 • Lưu trú dữ liệu toàn cầu",
"heroCardTitle": "Trung tâm điều hành",
"heroCardSubtitle": "Sức khỏe danh mục trực tiếp",
"heroCardStatus": "Hệ thống ổn định",
"heroCardMetric1": "Giao hàng đúng hạn",
"heroCardMetric2": "Luồng công việc đang chạy",
"heroCardMetric3": "Cân bằng năng lực",
"heroCardFootnote": "Dữ liệu cập nhật mỗi 5 phút",
"trustedBy": "Được các đội tăng trưởng nhanh tin dùng",
"statsTitle": "Tín hiệu hiệu suất",
"statsSubtitle": "Những con số lớn thể hiện đà tăng trưởng.",
"statsNote": "Tổng hợp từ khách hàng đang hoạt động trong 12 tháng qua.",
"statTasks": "Nhiệm vụ được điều phối",
"statMilestones": "Cột mốc đúng hạn",
"statTeams": "Đội ngũ được triển khai",
"statCycleTime": "Giảm thời gian chu kỳ",
"statUptime": "Thời gian hoạt động",
"workflowTitle": "Cách vận hành",
"workflowSubtitle": "Từ khởi động đến kết thúc, mọi chi tiết đều đồng bộ.",
"workflowStep1Title": "Căn chỉnh danh mục",
"workflowStep1Text": "Xác định mục tiêu, ngân sách và trách nhiệm cho từng chương trình.",
"workflowStep2Title": "Xây dựng kế hoạch",
"workflowStep2Text": "Tạo roadmap, phụ thuộc và kế hoạch nhân sự trong vài phút.",
"workflowStep3Title": "Thực thi rõ ràng",
"workflowStep3Text": "Tự động hóa trạng thái, cảnh báo rủi ro và cập nhật cho stakeholder.",
"workflowStep4Title": "Báo cáo tự tin",
"workflowStep4Text": "Cung cấp insight sẵn sàng cho lãnh đạo với số liệu trực tiếp.",
"capabilitiesTitle": "Năng lực",
"capabilitiesSubtitle": "Tất cả những gì bạn cần để vận hành PMO chính xác.",
"capability1Title": "Không gian hợp nhất",
"capability1Text": "Một nơi cho roadmap, nhiệm vụ, tài liệu và phê duyệt.",
"capability2Title": "Tự động hóa quy trình",
"capability2Text": "Chuẩn hóa giao hàng và loại bỏ việc đuổi theo trạng thái thủ công.",
"capability3Title": "Trung tâm stakeholder",
"capability3Text": "Tập trung trao đổi, quyết định và trách nhiệm.",
"capability4Title": "Phân tích trực tiếp",
"capability4Text": "Theo dõi tốc độ, chi phí và tác động theo thời gian thực.",
"capability5Title": "Căn chỉnh mục tiêu",
"capability5Text": "Liên kết mọi sáng kiến với kết quả và chủ đề chiến lược.",
"capability6Title": "Dự báo danh mục",
"capability6Text": "Mô phỏng kịch bản và dự báo độ tin cậy giao hàng.",
"commandTitle": "Điều hành danh mục",
"commandSubtitle": "Điều phối mọi chuyển động.",
"commandBullet1": "Dashboard đa dự án với khả năng drill-down.",
"commandBullet2": "Cảnh báo tự động khi lệch tiến độ hoặc ngân sách.",
"commandBullet3": "Báo cáo cho lãnh đạo trong vài giây.",
"commandBullet4": "Góc nhìn theo vai trò cho từng stakeholder.",
"commandMetricTitle": "Tác động gần đây",
"commandMetricSubtitle": "Cải thiện theo quý trên toàn bộ giao hàng.",
"commandMetricValue1Label": "Chu kỳ nhanh hơn",
"commandMetricValue2Label": "Ít leo thang hơn",
"commandMetricValue3Label": "Giải phóng năng lực",
"storiesTitle": "Kết quả khách hàng",
"storiesSubtitle": "Đội ngũ thật. Cải thiện thật.",
"story1Quote": "Chúng tôi hợp nhất 12 danh mục vào một màn hình và cuối cùng đạt đúng hạn.",
"story1Name": "Avery Park",
"story1Role": "VP, Quản lý chương trình",
"story1Company": "Northwind",
"story1MetricLabel": "Đúng hạn",
"story2Quote": "Collabify thay thế năm công cụ và tạo một nguồn dữ liệu duy nhất cho lãnh đạo.",
"story2Name": "Nina Holt",
"story2Role": "Giám đốc vận hành",
"story2Company": "SignalForge",
"story2MetricLabel": "Tốc độ quyết định",
"story3Quote": "PMO của chúng tôi nhận diện rủi ro trước khi ảnh hưởng sản xuất.",
"story3Name": "Mateo Ruiz",
"story3Role": "Trưởng PMO",
"story3Company": "Everlane",
"story3MetricLabel": "Giảm rủi ro",
"securityTitle": "Bảo mật & tuân thủ",
"securitySubtitle": "Bảo vệ cấp doanh nghiệp mà không làm chậm đội ngũ.",
"security1Title": "Mã hóa dữ liệu",
"security1Text": "AES-256 khi lưu trữ và TLS 1.2+ khi truyền tải.",
"security2Title": "Quản trị truy cập",
"security2Text": "Phân quyền chi tiết, SSO và nhật ký kiểm toán cho đội ngũ cần tuân thủ.",
"security3Title": "Độ tin cậy",
"security3Text": "Hạ tầng toàn cầu với dự phòng nhiều vùng.",
"faqTitle": "Câu hỏi thường gặp",
"faqSubtitle": "Giải đáp cho đội ngũ đang đánh giá Collabify.",
"faq1Question": "Mất bao lâu để onboard một danh mục?",
"faq1Answer": "Phần lớn đội ngũ khởi chạy trong hai tuần với template và di chuyển có hướng dẫn.",
"faq2Question": "Collabify có hỗ trợ báo cáo đa đơn vị không?",
"faq2Answer": "Có. Tổng hợp theo đơn vị kinh doanh, khu vực hoặc chủ đề chiến lược.",
"faq3Question": "Có thể tùy chỉnh quy trình và phê duyệt không?",
"faq3Answer": "Hoàn toàn. Cấu hình giai đoạn, quy tắc và thông báo theo từng nhóm.",
"faq4Question": "Các tiêu chuẩn bảo mật được hỗ trợ?",
"faq4Answer": "Tuân theo SOC 2 và GDPR, có tùy chọn lưu trữ dữ liệu theo khu vực.",
"finalCTA": "Sẵn sàng nâng tầm giao hàng?",
"finalCTASubtitle": "Đưa toàn bộ danh mục vào tầm nhìn với Collabify.",
"startCollabifying": "Bắt đầu với Collabify"
}
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the English locale file, this Vietnamese translation file has been completely rewritten with entirely new content (from 29 to 103 keys), transforming the application's messaging and branding. This is not a minor documentation improvement as stated in the PR description, but a substantial content change that should be clearly documented.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation duplicate This issue or pull request already exists enhancement New feature or request good first issue Good for newcomers help wanted Extra attention is needed

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants