From f90ed4bee9f6aed2cdec29176b3bb7aa2944987d Mon Sep 17 00:00:00 2001 From: Baptiste <68440638+Baptiiiiste@users.noreply.github.com> Date: Wed, 12 Nov 2025 16:32:56 +0100 Subject: [PATCH 1/6] UPD - Lint --- app/[locale]/page.tsx | 22 +- .../(auth)/landing/EffortlessIntegration.tsx | 422 ------------ .../pages/(auth)/landing/NumbersThatSpeak.tsx | 600 ------------------ .../(auth)/landing/SmartSimpleBrilliant.tsx | 560 ---------------- .../(auth)/landing/TestimonialSection.tsx | 167 ----- .../pages/(auth)/landing/YourWorkInSync.tsx | 333 ---------- .../pages/(auth)/sign-in/SignInForm.tsx | 2 +- .../pages/(auth)/sign-up/SignUpForm.tsx | 2 +- .../(root)/Webhooks/WebhookUsageCard.tsx | 1 - components/ui/chart.tsx | 104 +-- components/ui/progress.tsx | 12 +- lib/actions/auth/authorize-google.action.ts | 3 +- lib/auth/config.ts | 2 +- 13 files changed, 73 insertions(+), 2157 deletions(-) delete mode 100644 components/pages/(auth)/landing/EffortlessIntegration.tsx delete mode 100644 components/pages/(auth)/landing/NumbersThatSpeak.tsx delete mode 100644 components/pages/(auth)/landing/SmartSimpleBrilliant.tsx delete mode 100644 components/pages/(auth)/landing/TestimonialSection.tsx delete mode 100644 components/pages/(auth)/landing/YourWorkInSync.tsx diff --git a/app/[locale]/page.tsx b/app/[locale]/page.tsx index a11f02e..87e111f 100644 --- a/app/[locale]/page.tsx +++ b/app/[locale]/page.tsx @@ -4,19 +4,15 @@ import type React from 'react' import { useState, useEffect, useRef } from 'react' import { DocumentationSection } from '@/components/pages/(auth)/landing/DocumentationSection' -import { TestimonialsSection } from '@/components/pages/(auth)/landing/TestimonialSection' import { PricingSection } from '@/components/pages/(auth)/landing/PrincingSection' import { FAQSection } from '@/components/pages/(auth)/landing/FaqSection' import { CTASection } from '@/components/pages/(auth)/landing/CtaSection' import { FooterSection } from '@/components/pages/(auth)/landing/FooterSection' -import NumbersThatSpeak from '@/components/pages/(auth)/landing/NumbersThatSpeak' -import EffortlessIntegration from '@/components/pages/(auth)/landing/EffortlessIntegration' -import YourWorkInSync from '@/components/pages/(auth)/landing/YourWorkInSync' -import SmartSimpleBrilliant from '@/components/pages/(auth)/landing/SmartSimpleBrilliant' import { SITENAME } from '@/constants/globals' import { LANDING_PAGE_LINKS, ROUTES } from '@/constants/routes' import { Link } from '@/lib/i18n/navigation' import { useTranslations } from 'next-intl' +import Image from 'next/image' function Badge({ icon, text }: { icon: React.ReactNode; text: string }) { return ( @@ -143,7 +139,10 @@ export default function LandingPage() {
- + {t('Buttons.CTA')}
@@ -151,7 +150,7 @@ export default function LandingPage() {
-
} - text={t("Trusted.Badge")} + text={t('Trusted.Badge')} />
- {t("Trusted.Title")} + {t('Trusted.Title')}
- {t("Trusted.Description")} + {t('Trusted.Description')}
@@ -421,7 +419,7 @@ export default function LandingPage() { `} >
- Horizon = ({ - width = 482, - height = 300, - className = '', -}) => { - const centerX = 250 - const centerY = 179 - const rings = [ - { radius: 80, logos: 2 }, // Inner ring - 2 logos - { radius: 120, logos: 3 }, // Middle ring - 3 logos - { radius: 160, logos: 2 }, // Outer ring - 2 logos - ] - - const getPositionOnRing = (ringRadius: number, angle: number) => ({ - x: centerX + ringRadius * Math.cos(angle), - y: centerY + ringRadius * Math.sin(angle), - }) - - return ( -
-
- - {/* Outer ring */} -
- {/* Middle ring */} -
- {/* Inner ring */} -
- - {/* Company logos positioned systematically on ring axes */} -
- {/* Central hub */} -
- b -
- - {/* GitHub - 180° (left) */} -
- GitHub -
- - {/* Slack - 0° (right) */} -
- Slack -
- - {/* Figma - 315° (top-right) */} -
- Figma -
- - {/* Discord - 135° (bottom-left) */} -
- Discord -
- - {/* Notion - 225° (bottom-left diagonal) */} -
- Notion -
- - {/* Stripe - 180° (left) */} -
- Stripe -
- - {/* Framer - 0° (right) */} -
- Framer -
- - - - - - - - - - - {/* Inner ring connections */} - - - - {/* Middle ring connections */} - - - - - {/* Outer ring connections */} - - - -
-
- ) -} - -export default EffortlessIntegration diff --git a/components/pages/(auth)/landing/NumbersThatSpeak.tsx b/components/pages/(auth)/landing/NumbersThatSpeak.tsx deleted file mode 100644 index 76e78f5..0000000 --- a/components/pages/(auth)/landing/NumbersThatSpeak.tsx +++ /dev/null @@ -1,600 +0,0 @@ -import type React from 'react' - -interface NumbersThatSpeakProps { - /** Fixed width from Figma: 482px */ - width?: number | string - /** Fixed height from Figma: 300px */ - height?: number | string - /** Optional className to pass to root */ - className?: string - /** Theme palette */ - theme?: 'light' | 'dark' -} - -/** - * Numbers that speak – Financial dashboard with layered charts - * Generated from Figma via MCP with exact measurements (482×300px) - * Single-file component following the v0-ready pattern used in this repo. - */ -const NumbersThatSpeak: React.FC = ({ - width = 482, - height = 300, - className = '', - theme = 'dark', -}) => { - // Design tokens (derived from Figma local variables) - const themeVars = - theme === 'light' - ? { - '--nts-surface': '#ffffff', - '--nts-text-primary': '#2f3037', - '--nts-text-secondary': 'rgba(47,48,55,0.8)', - '--nts-text-muted': 'rgba(55,50,47,0.7)', - '--nts-border': 'rgba(47,48,55,0.12)', - '--nts-shadow': 'rgba(47,48,55,0.06)', - } - : ({ - '--nts-surface': '#ffffff', - '--nts-text-primary': '#2f3037', - '--nts-text-secondary': 'rgba(47,48,55,0.8)', - '--nts-text-muted': 'rgba(55,50,47,0.7)', - '--nts-border': 'rgba(47,48,55,0.12)', - '--nts-shadow': 'rgba(47,48,55,0.06)', - } as React.CSSProperties) - - // Figma-exported assets - const imgSchedule = '/placeholder.svg?height=271&width=431' - const imgYAxisLine = '/placeholder.svg?height=17&width=295' - const imgYAxisLine1 = '/placeholder.svg?height=13&width=295' - const imgYAxisLine2 = '/placeholder.svg?height=13&width=295' - - return ( -
- {/* Root positioning container - exact match to Figma */} -
- {/* Small dashboard card - back layer */} -
-
-
-
-
- - {/* Medium dashboard card - middle layer */} -
-
-
-
-
- - {/* Large dashboard card - front layer with full content */} -
-
-
-
-
-
-
- {/* Header Section */} -
-
-
- Invoiced Revenue -
-
- $317,731.00 -
-
-
- - {/* Chart Container */} -
-
- {/* Chart Axis */} -
-
- {/* Y-Axis Labels */} -
-
- {['500k', '300k', '200k', '100k', '0'].map( - (label, index) => ( -
-
- {label} -
-
- ), - )} -
-
- - {/* Grid Lines and X-Axis */} -
- {/* Grid Lines */} -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - {/* X-Axis Labels */} -
-
- Aug 2023 -
-
- Aug 2024 -
-
-
-
-
- - {/* Chart Data Bars */} -
-
- {[ - { height: '83px', color: '#5D4E37' }, - { height: '108px', color: '#5D4E37' }, - { height: '58px', color: '#5D4E37' }, - { height: '89px', color: '#5D4E37' }, - { height: '83px', color: '#5D4E37' }, - { height: '89px', color: '#5D4E37' }, - { height: '83px', color: '#5D4E37' }, - { height: '95px', color: '#5D4E37' }, - { height: '108px', color: '#5D4E37' }, - { height: '76px', color: '#5D4E37' }, - { height: '89px', color: '#5D4E37' }, - ].map((item, index) => ( -
- ))} -
-
-
-
-
-
-
-
-
-
-
-
-
- ) -} - -export default NumbersThatSpeak diff --git a/components/pages/(auth)/landing/SmartSimpleBrilliant.tsx b/components/pages/(auth)/landing/SmartSimpleBrilliant.tsx deleted file mode 100644 index c0e91c2..0000000 --- a/components/pages/(auth)/landing/SmartSimpleBrilliant.tsx +++ /dev/null @@ -1,560 +0,0 @@ -import type React from 'react' - -interface SmartSimpleBrilliantProps { - /** Fixed width from Figma: 482px */ - width?: number | string - /** Fixed height from Figma: 300px */ - height?: number | string - /** Optional className to pass to root */ - className?: string - /** Theme palette */ - theme?: 'light' | 'dark' -} - -/** - * Smart · Simple · Brilliant – Calendar cards - * Generated from Figma via MCP with exact measurements (482×300px) - * Single-file component following the v0-ready pattern used in this repo. - */ -const SmartSimpleBrilliant: React.FC = ({ - width = 482, - height = 300, - className = '', - theme = 'dark', -}) => { - // Design tokens (derived from Figma local variables) - const themeVars = - theme === 'light' - ? { - '--ssb-surface': '#ffffff', - '--ssb-text': '#1b1919', - '--ssb-border': 'rgba(0,0,0,0.08)', - '--ssb-inner-border': 'rgba(0,0,0,0.12)', - '--ssb-shadow': 'rgba(0,0,0,0.12)', - } - : ({ - '--ssb-surface': '#333937', - '--ssb-text': '#f8f8f8', - '--ssb-border': 'rgba(255,255,255,0.16)', - '--ssb-inner-border': 'rgba(255,255,255,0.12)', - '--ssb-shadow': 'rgba(0,0,0,0.28)', - } as React.CSSProperties) - - // Figma-exported SVG assets used for small icons - const img = - 'http://localhost:3845/assets/1b1e60b441119fb176db990a3c7fe2670a764855.svg' - const img1 = - 'http://localhost:3845/assets/a502f04ccfc3811f304b58a3a982a5b6fa070e91.svg' - const img2 = - 'http://localhost:3845/assets/9c07375bf3b9f1f1d8a0a24447829eb6f54fa928.svg' - const img3 = - 'http://localhost:3845/assets/19500d66798ef5ea9dc9d5f971cd0e9c29674bd3.svg' - - return ( -
-
- {/* Left tilted card group */} -
-
-
- {/* Amber event */} -
-
-
-
- - 2:00 - - - PM - -
-
- video -
-
-
-
- 1:1 with Heather -
-
-
- - {/* Sky event */} -
-
-
-
- - 2:00 - - - PM - -
-
- video -
-
-
-
- Concept Design Review II -
-
-
- - {/* Emerald event */} -
-
-
-
- - 9:00 - - - AM - -
-
- Webinar: Figma ... -
-
-
-
-
-
- - {/* Right card */} -
-
-
- {/* Violet event */} -
-
-
-
- - 11:00 - - - AM - -
-
- video -
-
-
-
- Onboarding Presentation -
-
-
- - {/* Rose event */} -
-
-
-
- - 4:00 - - - PM - -
-
- video -
-
-
-
- 🍷 Happy Hour -
-
-
- - {/* Violet tall event */} -
-
-
-
- - 11:00 - - - AM - -
-
- 🍔 New Employee Welcome Lunch! -
-
-
-
-
-
-
-
- ) -} - -export default SmartSimpleBrilliant diff --git a/components/pages/(auth)/landing/TestimonialSection.tsx b/components/pages/(auth)/landing/TestimonialSection.tsx deleted file mode 100644 index 15f047a..0000000 --- a/components/pages/(auth)/landing/TestimonialSection.tsx +++ /dev/null @@ -1,167 +0,0 @@ -'use client' - -import { useState, useEffect } from 'react' -import type React from 'react' - -export function TestimonialsSection() { - const [activeTestimonial, setActiveTestimonial] = useState(0) - const [isTransitioning, setIsTransitioning] = useState(false) - - const testimonials = [ - { - quote: - 'In just a few minutes, we transformed our data into actionable insights. The process was seamless and incredibly efficient!', - name: 'Jamie Marshall', - company: 'Co-founder, Exponent', - image: - 'https://hebbkx1anhila5yf.public.blob.vercel-storage.com/ChatGPT%20Image%20Sep%2011%2C%202025%2C%2011_35_19%20AM-z4zSRLsbOQDp7MJS1t8EXmGNB6Al9Z.png', - }, - { - quote: - 'Brillance has revolutionized how we handle custom contracts. The automation saves us hours every week and eliminates errors completely.', - name: 'Sarah Chen', - company: 'VP Operations, TechFlow', - image: - 'https://hebbkx1anhila5yf.public.blob.vercel-storage.com/ChatGPT%20Image%20Sep%2011%2C%202025%2C%2010_54_18%20AM-nbiecp92QNdTudmCrHr97uekrIPzCP.png', - }, - { - quote: - 'The billing automation is a game-changer. What used to take our team days now happens automatically with perfect accuracy.', - name: 'Marcus Rodriguez', - company: 'Finance Director, InnovateCorp', - image: - 'https://hebbkx1anhila5yf.public.blob.vercel-storage.com/ChatGPT%20Image%20Sep%2011%2C%202025%2C%2011_01_05%20AM-TBOe92trRxKn4G5So1m9D2h7LRH4PG.png', - }, - ] - - useEffect(() => { - const interval = setInterval(() => { - setIsTransitioning(true) - setTimeout(() => { - setActiveTestimonial((prev) => (prev + 1) % testimonials.length) - setTimeout(() => { - setIsTransitioning(false) - }, 100) - }, 300) - }, 12000) // increased from 6000ms to 12000ms for longer testimonial display - - return () => clearInterval(interval) - }, [testimonials.length]) - - const handleNavigationClick = (index: number) => { - setIsTransitioning(true) - setTimeout(() => { - setActiveTestimonial(index) - setTimeout(() => { - setIsTransitioning(false) - }, 100) - }, 300) - } - - return ( -
- {/* Header Section */} - - {/* Testimonial Content */} -
-
-
- {testimonials[activeTestimonial].name} -
-
- "{testimonials[activeTestimonial].quote}" -
-
-
- {testimonials[activeTestimonial].name} -
-
- {testimonials[activeTestimonial].company} -
-
-
-
- - {/* Navigation Arrows */} -
- - -
-
-
-
- ) -} diff --git a/components/pages/(auth)/landing/YourWorkInSync.tsx b/components/pages/(auth)/landing/YourWorkInSync.tsx deleted file mode 100644 index 064f698..0000000 --- a/components/pages/(auth)/landing/YourWorkInSync.tsx +++ /dev/null @@ -1,333 +0,0 @@ -import type React from 'react' - -interface YourWorkInSyncProps { - /** Fixed width from Figma: 482px */ - width?: number | string - /** Fixed height from Figma: 300px */ - height?: number | string - /** Optional className to pass to root */ - className?: string - /** Theme palette */ - theme?: 'light' | 'dark' -} - -/** - * Your work, in sync – Chat conversation UI - * Generated from Figma via MCP with exact measurements (482×300px) - * Single-file component following the v0-ready pattern used in this repo. - */ -const YourWorkInSync: React.FC = ({ - width = 482, - height = 300, - className = '', - theme = 'dark', -}) => { - // Design tokens (derived from Figma local variables) - const themeVars = - theme === 'light' - ? { - '--yws-surface': '#ffffff', - '--yws-text-primary': '#37322f', - '--yws-text-secondary': '#6b7280', - '--yws-bubble-light': '#e8e5e3', - '--yws-bubble-dark': '#37322f', - '--yws-bubble-white': '#ffffff', - '--yws-border': 'rgba(0,0,0,0.08)', - '--yws-shadow': 'rgba(0,0,0,0.08)', - } - : ({ - '--yws-surface': '#1f2937', - '--yws-text-primary': '#f9fafb', - '--yws-text-secondary': '#d1d5db', - '--yws-bubble-light': '#374151', - '--yws-bubble-dark': '#111827', - '--yws-bubble-white': '#ffffff', - '--yws-border': 'rgba(255,255,255,0.12)', - '--yws-shadow': 'rgba(0,0,0,0.24)', - } as React.CSSProperties) - - // Figma-exported assets - const imgFrame2147223205 = - '/professional-woman-avatar-with-short-brown-hair-an.jpg' - const imgFrame2147223206 = - '/professional-man-avatar-with-beard-and-glasses-loo.jpg' - const imgFrame2147223207 = - '/professional-person-avatar-with-curly-hair-and-war.jpg' - const imgArrowUp = - "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='currentColor' strokeWidth='3' strokeLinecap='round' strokeLinejoin='round'%3E%3Cpath d='m5 12 7-7 7 7'/%3E%3Cpath d='M12 19V5'/%3E%3C/svg%3E" - - return ( -
- {/* Root frame size 482×300 – content centered */} -
- {/* Remove the flip transformation and position messages normally */} -
- {/* Message 1: Left side with avatar */} -
- {/* Avatar */} -
- {/* Message bubble */} -
- - Team updates flow seamlessly - -
-
- - {/* Message 2: Right side with avatar */} -
- {/* Message bubble */} -
- - Hi everyone - -
- {/* Avatar */} -
-
- - {/* Message 3: Left side with avatar */} -
- {/* Avatar */} -
- {/* Message bubble */} -
- - How about this instead? - -
-
- - {/* Message 4: Center with send button */} -
- {/* Message bubble */} -
- - Great work, everyone! - -
- {/* Send button */} -
- Send -
-
-
-
-
- ) -} - -export default YourWorkInSync diff --git a/components/pages/(auth)/sign-in/SignInForm.tsx b/components/pages/(auth)/sign-in/SignInForm.tsx index 5e4653e..ba1fe35 100644 --- a/components/pages/(auth)/sign-in/SignInForm.tsx +++ b/components/pages/(auth)/sign-in/SignInForm.tsx @@ -28,7 +28,7 @@ import { ENABLED_AUTH_PROVIDERS } from '@/constants/auth' interface Props { action: FormActionCallback - googleAuthAction: any + googleAuthAction: () => Promise } export function SignInForm({ action }: Props) { diff --git a/components/pages/(auth)/sign-up/SignUpForm.tsx b/components/pages/(auth)/sign-up/SignUpForm.tsx index 11bf32a..b4d9a4d 100644 --- a/components/pages/(auth)/sign-up/SignUpForm.tsx +++ b/components/pages/(auth)/sign-up/SignUpForm.tsx @@ -28,7 +28,7 @@ import { ENABLED_AUTH_PROVIDERS } from '@/constants/auth' interface Props { action: FormActionCallback - googleAuthAction: any + googleAuthAction: () => Promise } export function SignUpForm({ action }: Props) { diff --git a/components/pages/(root)/Webhooks/WebhookUsageCard.tsx b/components/pages/(root)/Webhooks/WebhookUsageCard.tsx index b224983..ade9ebb 100644 --- a/components/pages/(root)/Webhooks/WebhookUsageCard.tsx +++ b/components/pages/(root)/Webhooks/WebhookUsageCard.tsx @@ -27,7 +27,6 @@ export async function WebhookUsageCard({ url }: Props) { - diff --git a/components/ui/chart.tsx b/components/ui/chart.tsx index 97cc280..63b2240 100644 --- a/components/ui/chart.tsx +++ b/components/ui/chart.tsx @@ -1,12 +1,12 @@ -"use client" +'use client' -import * as React from "react" -import * as RechartsPrimitive from "recharts" +import * as React from 'react' +import * as RechartsPrimitive from 'recharts' -import { cn } from "@/lib/utils" +import { cn } from '@/lib/utils' // Format: { THEME_NAME: CSS_SELECTOR } -const THEMES = { light: "", dark: ".dark" } as const +const THEMES = { light: '', dark: '.dark' } as const export type ChartConfig = { [k in string]: { @@ -28,7 +28,7 @@ function useChart() { const context = React.useContext(ChartContext) if (!context) { - throw new Error("useChart must be used within a ") + throw new Error('useChart must be used within a ') } return context @@ -40,14 +40,14 @@ function ChartContainer({ children, config, ...props -}: React.ComponentProps<"div"> & { +}: React.ComponentProps<'div'> & { config: ChartConfig children: React.ComponentProps< typeof RechartsPrimitive.ResponsiveContainer - >["children"] + >['children'] }) { const uniqueId = React.useId() - const chartId = `chart-${id || uniqueId.replace(/:/g, "")}` + const chartId = `chart-${id || uniqueId.replace(/:/g, '')}` return ( @@ -56,7 +56,7 @@ function ChartContainer({ data-chart={chartId} className={cn( "[&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border flex aspect-video justify-center text-xs [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden", - className + className, )} {...props} > @@ -71,7 +71,7 @@ function ChartContainer({ const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => { const colorConfig = Object.entries(config).filter( - ([, config]) => config.theme || config.color + ([, config]) => config.theme || config.color, ) if (!colorConfig.length) { @@ -92,11 +92,11 @@ ${colorConfig itemConfig.color return color ? ` --color-${key}: ${color};` : null }) - .join("\n")} + .join('\n')} } -` +`, ) - .join("\n"), + .join('\n'), }} /> ) @@ -108,7 +108,7 @@ function ChartTooltipContent({ active, payload, className, - indicator = "dot", + indicator = 'dot', hideLabel = false, hideIndicator = false, label, @@ -119,10 +119,10 @@ function ChartTooltipContent({ nameKey, labelKey, }: React.ComponentProps & - React.ComponentProps<"div"> & { + React.ComponentProps<'div'> & { hideLabel?: boolean hideIndicator?: boolean - indicator?: "line" | "dot" | "dashed" + indicator?: 'line' | 'dot' | 'dashed' nameKey?: string labelKey?: string }) { @@ -134,16 +134,16 @@ function ChartTooltipContent({ } const [item] = payload - const key = `${labelKey || item?.dataKey || item?.name || "value"}` + const key = `${labelKey || item?.dataKey || item?.name || 'value'}` const itemConfig = getPayloadConfigFromPayload(config, item, key) const value = - !labelKey && typeof label === "string" + !labelKey && typeof label === 'string' ? config[label as keyof typeof config]?.label || label : itemConfig?.label if (labelFormatter) { return ( -
+
{labelFormatter(value, payload)}
) @@ -153,7 +153,7 @@ function ChartTooltipContent({ return null } - return
{value}
+ return
{value}
}, [ label, labelFormatter, @@ -168,19 +168,19 @@ function ChartTooltipContent({ return null } - const nestLabel = payload.length === 1 && indicator !== "dot" + const nestLabel = payload.length === 1 && indicator !== 'dot' return (
{!nestLabel ? tooltipLabel : null}
{payload.map((item, index) => { - const key = `${nameKey || item.name || item.dataKey || "value"}` + const key = `${nameKey || item.name || item.dataKey || 'value'}` const itemConfig = getPayloadConfigFromPayload(config, item, key) const indicatorColor = color || item.payload.fill || item.color @@ -188,8 +188,8 @@ function ChartTooltipContent({
svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5", - indicator === "dot" && "items-center" + '[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5', + indicator === 'dot' && 'items-center', )} > {formatter && item?.value !== undefined && item.name ? ( @@ -202,19 +202,19 @@ function ChartTooltipContent({ !hideIndicator && (
@@ -222,8 +222,8 @@ function ChartTooltipContent({ )}
@@ -254,10 +254,10 @@ function ChartLegendContent({ className, hideIcon = false, payload, - verticalAlign = "bottom", + verticalAlign = 'bottom', nameKey, -}: React.ComponentProps<"div"> & - Pick & { +}: React.ComponentProps<'div'> & + Pick & { hideIcon?: boolean nameKey?: string }) { @@ -270,20 +270,20 @@ function ChartLegendContent({ return (
{payload.map((item) => { - const key = `${nameKey || item.dataKey || "value"}` + const key = `${nameKey || item.dataKey || 'value'}` const itemConfig = getPayloadConfigFromPayload(config, item, key) return (
svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3" + '[&>svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3', )} > {itemConfig?.icon && !hideIcon ? ( @@ -308,15 +308,15 @@ function ChartLegendContent({ function getPayloadConfigFromPayload( config: ChartConfig, payload: unknown, - key: string + key: string, ) { - if (typeof payload !== "object" || payload === null) { + if (typeof payload !== 'object' || payload === null) { return undefined } const payloadPayload = - "payload" in payload && - typeof payload.payload === "object" && + 'payload' in payload && + typeof payload.payload === 'object' && payload.payload !== null ? payload.payload : undefined @@ -325,13 +325,13 @@ function getPayloadConfigFromPayload( if ( key in payload && - typeof payload[key as keyof typeof payload] === "string" + typeof payload[key as keyof typeof payload] === 'string' ) { configLabelKey = payload[key as keyof typeof payload] as string } else if ( payloadPayload && key in payloadPayload && - typeof payloadPayload[key as keyof typeof payloadPayload] === "string" + typeof payloadPayload[key as keyof typeof payloadPayload] === 'string' ) { configLabelKey = payloadPayload[ key as keyof typeof payloadPayload diff --git a/components/ui/progress.tsx b/components/ui/progress.tsx index e7a416c..ab38305 100644 --- a/components/ui/progress.tsx +++ b/components/ui/progress.tsx @@ -1,9 +1,9 @@ -"use client" +'use client' -import * as React from "react" -import * as ProgressPrimitive from "@radix-ui/react-progress" +import * as React from 'react' +import * as ProgressPrimitive from '@radix-ui/react-progress' -import { cn } from "@/lib/utils" +import { cn } from '@/lib/utils' function Progress({ className, @@ -14,8 +14,8 @@ function Progress({ diff --git a/lib/actions/auth/authorize-google.action.ts b/lib/actions/auth/authorize-google.action.ts index 3f0e9da..e85fbbd 100644 --- a/lib/actions/auth/authorize-google.action.ts +++ b/lib/actions/auth/authorize-google.action.ts @@ -1,8 +1,9 @@ 'use server' import { upsertGoogleService } from '@/services/auth/upsert-google.service' +import type { GoogleProfile } from 'next-auth/providers/google' -export async function authorizeGoogleAction(profile: any) { +export async function authorizeGoogleAction(profile: GoogleProfile) { const user = await upsertGoogleService(profile.email, profile.name) return { diff --git a/lib/auth/config.ts b/lib/auth/config.ts index d4a020c..32579bd 100644 --- a/lib/auth/config.ts +++ b/lib/auth/config.ts @@ -55,7 +55,7 @@ export const AUTH_CONFIG: NextAuthConfig = { } return session }, - async redirect({ url, baseUrl }) { + async redirect() { return `/${ROUTES.DASHBOARD}` }, }, From 18329c49a45d4b78dd803df098dabcc38145fa9c Mon Sep 17 00:00:00 2001 From: Baptiste <68440638+Baptiiiiste@users.noreply.github.com> Date: Mon, 17 Nov 2025 14:42:19 +0100 Subject: [PATCH 2/6] ADD - Implement CI workflow (#4) * ADD - Implement CI workflow * UPD - Refactor CI workflow to remove duplicate pnpm setup step * UPD - Refactor CI workflow to remove duplicate pnpm setup step * UPD - Simplify request handling by directly using params.uuid * UPD - Simplify request handling by directly using params.uuid * UPD - Simplify request handling by directly using params.uuid * UPD - Simplify request handling by directly using params.uuid * UPD - Update route parameter handling to use Promise for uuid extraction * UPD - Update route parameter handling to use Promise for uuid extraction * UPD - Enhance CI configuration by adding Docker metadata extraction and updating image tags * UPD - Enhance CI configuration by adding Docker metadata extraction and updating image tags * UPD - Add step to generate Prisma Client in CI configuration * UPD - Add step to generate Prisma Client in CI configuration * UPD - Update Dockerfile to generate Prisma Client and optimize production dependencies * UPD - Update Dockerfile to generate Prisma Client and optimize production dependencies * UPD - Refactor CI configuration to improve environment variable handling and streamline deployment conditions * UPD - Simplify CI configuration by removing environment input and directly setting deployment environments * UPD - Update CI configuration to enforce manual deployment conditions for dev and prod environments * UPD - Add CI workflows for manual deployment to DEV and PROD environments * UPD - Enhance CI configuration to support manual deployment to DEV and PROD environments * UPD - CI * UPD - CI * UPD - CI * UPD - CI * UPD - CI * UPD - CI * UPD - CI * UPD - CI * UPD - CI --- .github/workflows/ci.yml | 140 ++++++++++++++++++++ Dockerfile | 80 ++++++++--- app/api/[uuid]/route.ts | 16 +-- components/shared/breadcrumb/Breadcrumb.tsx | 55 -------- 4 files changed, 213 insertions(+), 78 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 components/shared/breadcrumb/Breadcrumb.tsx diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..654f925 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,140 @@ +name: "DEV - CI/CD" + +on: + pull_request: + types: [opened, synchronize, reopened] + branches: + - develop + - main + workflow_dispatch: + +jobs: + # 1️⃣ Build & tests + build-and-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v3 + with: + version: 9 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Generate Prisma Client + run: pnpm prisma generate + + - name: Skip tests (no test script defined) + run: echo "⚠️ Aucun test défini, étape ignorée." + + - name: Build app + run: pnpm build + + + # 2️⃣ Build & push Docker image + docker-build-push: + runs-on: ubuntu-latest + needs: build-and-test + permissions: + contents: read + packages: write + + env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=raw,value=latest + type=sha,format=long + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + build-args: | + NEXT_PUBLIC_ENV=${{ github.base_ref }} + + + # 3️⃣ Deploy DEV + deploy-dev: + runs-on: self-hosted + needs: docker-build-push + + steps: + - name: Clean workspace + run: rm -rf * + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Pull new image + restart stack + run: | + echo "🔧 Deploying on the server..." + cd /home/baptiste/Dev/WPT/dev + docker-compose pull + docker rm -f wpt-dev_website || true + docker-compose up -d --remove-orphans + echo "🚀 Deployed in DEV!" + + deploy-prod: + runs-on: self-hosted + needs: docker-build-push + if: github.ref == 'refs/heads/main' + steps: + - name: Clean workspace + run: rm -rf * + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Pull new image + restart PROD stack + run: | + echo "🔧 Deploying on the server (PROD)..." + cd /home/baptiste/Dev/WPT/prod + docker-compose pull + docker rm -f wpt_website || true + docker-compose up -d --remove-orphans + echo "🚀 Deployed in PROD!" diff --git a/Dockerfile b/Dockerfile index 06f3486..412272e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,24 +1,74 @@ -# Étape 1 : build -FROM node:22-alpine AS builder +FROM node:22-alpine AS base + +# Install dependencies only when needed +FROM base AS deps +# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. +RUN apk add --no-cache libc6-compat openssl WORKDIR /app -RUN npm install -g pnpm + +# Install pnpm +RUN corepack enable && corepack prepare pnpm@latest --activate + +# Install dependencies based on pnpm COPY package.json pnpm-lock.yaml ./ -COPY .env .env -RUN pnpm install +RUN pnpm install --frozen-lockfile + +FROM base AS dev +WORKDIR /app +RUN corepack enable && corepack prepare pnpm@latest --activate +RUN apk add --no-cache openssl +COPY --from=deps /app/node_modules ./node_modules COPY . . + +# Generates prisma files +RUN pnpm prisma generate + +# Enables Hot Reloading Check https://github.com/vercel/next.js/issues/36774 for more information +ENV CHOKIDAR_USEPOLLING=true +ENV WATCHPACK_POLLING=true + +# Rebuild the source code only when needed +FROM base AS builder +WORKDIR /app +RUN corepack enable && corepack prepare pnpm@latest --activate +RUN apk add --no-cache openssl +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +ENV NEXT_TELEMETRY_DISABLED 1 + +# Generates prisma files for production build +RUN pnpm prisma generate RUN pnpm build -# Étape 2 : image finale propre -FROM node:22-alpine +# Production image, copy all the files and run next +FROM base AS runner WORKDIR /app -RUN npm install -g pnpm -COPY --from=builder /app/package.json /app/pnpm-lock.yaml ./ -COPY --from=builder /app/.next ./.next -COPY --from=builder /app/public ./public -COPY --from=builder /app/next.config.ts ./ -COPY --from=builder /app/tsconfig.json ./ -RUN pnpm install --prod +ENV NODE_ENV production +ENV NEXT_TELEMETRY_DISABLED 1 + +RUN apk add --no-cache openssl +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +# Install pnpm in runner +RUN corepack enable && corepack prepare pnpm@latest --activate + +# Copier les fichiers nécessaires +COPY --from=builder --chown=nextjs:nodejs /app/package.json ./ +COPY --from=builder --chown=nextjs:nodejs /app/pnpm-lock.yaml ./ +COPY --from=builder --chown=nextjs:nodejs /app/node_modules ./node_modules +COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next +COPY --from=builder --chown=nextjs:nodejs /app/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/prisma ./prisma +COPY --from=builder --chown=nextjs:nodejs /app/next.config.ts ./ + +USER nextjs EXPOSE 3000 -CMD ["pnpm", "start"] +ENV PORT 3000 +ENV HOSTNAME "0.0.0.0" + +# Prisma generate + db push + start +CMD sh -c "pnpm prisma generate && pnpm prisma db push --accept-data-loss && pnpm start" \ No newline at end of file diff --git a/app/api/[uuid]/route.ts b/app/api/[uuid]/route.ts index 7fa7895..e13ec06 100644 --- a/app/api/[uuid]/route.ts +++ b/app/api/[uuid]/route.ts @@ -51,50 +51,50 @@ async function handleRequest(req: NextRequest, uuid: string) { export async function GET( req: NextRequest, - { params }: { params: { uuid: string } }, + { params }: { params: Promise<{ uuid: string }> }, ) { const { uuid } = await params return handleRequest(req, uuid) } export async function POST( req: NextRequest, - { params }: { params: { uuid: string } }, + { params }: { params: Promise<{ uuid: string }> }, ) { const { uuid } = await params return handleRequest(req, uuid) } export async function PUT( req: NextRequest, - { params }: { params: { uuid: string } }, + { params }: { params: Promise<{ uuid: string }> }, ) { const { uuid } = await params return handleRequest(req, uuid) } export async function PATCH( req: NextRequest, - { params }: { params: { uuid: string } }, + { params }: { params: Promise<{ uuid: string }> }, ) { const { uuid } = await params return handleRequest(req, uuid) } export async function DELETE( req: NextRequest, - { params }: { params: { uuid: string } }, + { params }: { params: Promise<{ uuid: string }> }, ) { const { uuid } = await params return handleRequest(req, uuid) } export async function OPTIONS( req: NextRequest, - { params }: { params: { uuid: string } }, + { params }: { params: Promise<{ uuid: string }> }, ) { const { uuid } = await params return handleRequest(req, uuid) } export async function HEAD( req: NextRequest, - { params }: { params: { uuid: string } }, + { params }: { params: Promise<{ uuid: string }> }, ) { const { uuid } = await params return handleRequest(req, uuid) -} +} \ No newline at end of file diff --git a/components/shared/breadcrumb/Breadcrumb.tsx b/components/shared/breadcrumb/Breadcrumb.tsx deleted file mode 100644 index 068394e..0000000 --- a/components/shared/breadcrumb/Breadcrumb.tsx +++ /dev/null @@ -1,55 +0,0 @@ -'use client' - -import Link from 'next/link' -import { - Breadcrumb, - BreadcrumbItem, - BreadcrumbLink, - BreadcrumbList, - BreadcrumbPage, - BreadcrumbSeparator, -} from '@/components/ui/breadcrumb' -import { usePathname } from 'next/navigation' -import React from 'react' -import { BREADCRUMBS } from '@/constants/breadcrumbs' -import { BreadcrumbHeader } from '@/components/shared/breadcrumb/BreadcrumbHeader' - -export function BreadCrumb() { - const pathname = usePathname() - const segments = pathname.split('/').filter(Boolean) - const filteredSegments = segments.filter((segment) => isNaN(Number(segment))) - - return ( - - - - {filteredSegments.map((segment, index) => { - const href = - '/' + segments.slice(0, segments.indexOf(segment) + 1).join('/') - const isLast = index === filteredSegments.length - 1 - - const label = - BREADCRUMBS[`/${segment}`] ?? - BREADCRUMBS[segment] ?? - segment.charAt(0).toUpperCase() + segment.slice(1) - - return ( - - - {isLast ? ( - {label} - ) : ( - - {label} - - )} - - {!isLast && } - - ) - })} - - - - ) -} From 2acf9bdbdc101900799e9a0739b315b145ca08d5 Mon Sep 17 00:00:00 2001 From: Baptiste <68440638+Baptiiiiste@users.noreply.github.com> Date: Mon, 17 Nov 2025 15:00:03 +0100 Subject: [PATCH 3/6] UPD - CI (#6) --- .github/workflows/ci.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 654f925..ebf4007 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,11 @@ on: - develop - main workflow_dispatch: + inputs: + branch: + description: 'Branch to deploy' + required: true + default: 'main' jobs: # 1️⃣ Build & tests @@ -115,7 +120,7 @@ jobs: deploy-prod: runs-on: self-hosted needs: docker-build-push - if: github.ref == 'refs/heads/main' + if: ${{ github.event.inputs.branch == 'main' }} steps: - name: Clean workspace run: rm -rf * From 8b7bc5ad880695459a78081f195a6a0349cc4239 Mon Sep 17 00:00:00 2001 From: Baptiste <68440638+Baptiiiiste@users.noreply.github.com> Date: Mon, 17 Nov 2025 15:14:51 +0100 Subject: [PATCH 4/6] UPD - CICD (#7) * UPD - CI * UPD - CI --- .github/workflows/ci.yml | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ebf4007..58da2b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,12 +6,9 @@ on: branches: - develop - main - workflow_dispatch: - inputs: - branch: - description: 'Branch to deploy' - required: true - default: 'main' + push: + branches: + - main # pour que PROD puisse se déclencher automatiquement si besoin jobs: # 1️⃣ Build & tests @@ -45,7 +42,6 @@ jobs: - name: Build app run: pnpm build - # 2️⃣ Build & push Docker image docker-build-push: runs-on: ubuntu-latest @@ -88,8 +84,7 @@ jobs: build-args: | NEXT_PUBLIC_ENV=${{ github.base_ref }} - - # 3️⃣ Deploy DEV + # 3️⃣ Deploy DEV (auto sur PR) deploy-dev: runs-on: self-hosted needs: docker-build-push @@ -108,19 +103,20 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Pull new image + restart stack + - name: Pull new image + restart DEV stack run: | - echo "🔧 Deploying on the server..." + echo "🔧 Deploying on DEV..." cd /home/baptiste/Dev/WPT/dev docker-compose pull docker rm -f wpt-dev_website || true docker-compose up -d --remove-orphans echo "🚀 Deployed in DEV!" + # 4️⃣ Deploy PROD (skip par défaut, relançable sur main) deploy-prod: runs-on: self-hosted needs: docker-build-push - if: ${{ github.event.inputs.branch == 'main' }} + if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' steps: - name: Clean workspace run: rm -rf * @@ -137,7 +133,7 @@ jobs: - name: Pull new image + restart PROD stack run: | - echo "🔧 Deploying on the server (PROD)..." + echo "🔧 Deploying on PROD..." cd /home/baptiste/Dev/WPT/prod docker-compose pull docker rm -f wpt_website || true From a526053c7d1463c5c542a5f6825b21790083132a Mon Sep 17 00:00:00 2001 From: Baptiste <68440638+Baptiiiiste@users.noreply.github.com> Date: Mon, 17 Nov 2025 15:25:19 +0100 Subject: [PATCH 5/6] UPD - CI (#9) --- .github/workflows/{ci.yml => dev.yml} | 43 ++-------- .github/workflows/prod.yml | 110 ++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 35 deletions(-) rename .github/workflows/{ci.yml => dev.yml} (70%) create mode 100644 .github/workflows/prod.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/dev.yml similarity index 70% rename from .github/workflows/ci.yml rename to .github/workflows/dev.yml index 58da2b9..8cb3cd1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/dev.yml @@ -1,14 +1,15 @@ name: "DEV - CI/CD" on: + push: + branches: + - develop + - main pull_request: types: [opened, synchronize, reopened] branches: - develop - main - push: - branches: - - main # pour que PROD puisse se déclencher automatiquement si besoin jobs: # 1️⃣ Build & tests @@ -71,7 +72,7 @@ jobs: with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | - type=raw,value=latest + type=raw,value=dev-latest type=sha,format=long - name: Build and push Docker image @@ -82,9 +83,9 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} build-args: | - NEXT_PUBLIC_ENV=${{ github.base_ref }} + NEXT_PUBLIC_ENV=develop - # 3️⃣ Deploy DEV (auto sur PR) + # 3️⃣ Deploy DEV deploy-dev: runs-on: self-hosted needs: docker-build-push @@ -110,32 +111,4 @@ jobs: docker-compose pull docker rm -f wpt-dev_website || true docker-compose up -d --remove-orphans - echo "🚀 Deployed in DEV!" - - # 4️⃣ Deploy PROD (skip par défaut, relançable sur main) - deploy-prod: - runs-on: self-hosted - needs: docker-build-push - if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' - steps: - - name: Clean workspace - run: rm -rf * - - - name: Checkout code - uses: actions/checkout@v4 - - - name: Log in to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Pull new image + restart PROD stack - run: | - echo "🔧 Deploying on PROD..." - cd /home/baptiste/Dev/WPT/prod - docker-compose pull - docker rm -f wpt_website || true - docker-compose up -d --remove-orphans - echo "🚀 Deployed in PROD!" + echo "🚀 Deployed in DEV!" \ No newline at end of file diff --git a/.github/workflows/prod.yml b/.github/workflows/prod.yml new file mode 100644 index 0000000..7420b03 --- /dev/null +++ b/.github/workflows/prod.yml @@ -0,0 +1,110 @@ +name: "PROD - CI/CD" + +on: + push: + tags: + - 'v*.*.*' # Se déclenche sur les tags de version (ex: v1.0.0, v2.1.3) + +jobs: + # 1️⃣ Build & tests + build-and-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v3 + with: + version: 9 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Generate Prisma Client + run: pnpm prisma generate + + - name: Skip tests (no test script defined) + run: echo "⚠️ Aucun test défini, étape ignorée." + + - name: Build app + run: pnpm build + + # 2️⃣ Build & push Docker image + docker-build-push: + runs-on: ubuntu-latest + needs: build-and-test + permissions: + contents: read + packages: write + + env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=raw,value=latest + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha,format=long + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + build-args: | + NEXT_PUBLIC_ENV=production + + # 3️⃣ Deploy PROD + deploy-prod: + runs-on: self-hosted + needs: docker-build-push + + steps: + - name: Clean workspace + run: rm -rf * + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Pull new image + restart PROD stack + run: | + echo "🔧 Deploying on PROD..." + cd /home/baptiste/Dev/WPT/prod + docker-compose pull + docker rm -f wpt_website || true + docker-compose up -d --remove-orphans + echo "🚀 Deployed in PROD!" \ No newline at end of file From 94d8a3b93e43d70c3133e561781bce7e511361cc Mon Sep 17 00:00:00 2001 From: Baptiste <68440638+Baptiiiiste@users.noreply.github.com> Date: Mon, 17 Nov 2025 17:55:33 +0100 Subject: [PATCH 6/6] UPD - CI --- .github/workflows/prod.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/prod.yml b/.github/workflows/prod.yml index 7420b03..f20f74f 100644 --- a/.github/workflows/prod.yml +++ b/.github/workflows/prod.yml @@ -106,5 +106,6 @@ jobs: cd /home/baptiste/Dev/WPT/prod docker-compose pull docker rm -f wpt_website || true + docker-compose up -d --no-deps wpt_website docker-compose up -d --remove-orphans - echo "🚀 Deployed in PROD!" \ No newline at end of file + echo "🚀 Deployed in PROD!"