6 Commits

Author SHA1 Message Date
6ee3dfdb87 release: promote 1.0.2 to production
All checks were successful
Tests / Backend - Tests passed: 8
THE-TIP-TOP-MULTIBRANCH/pipeline/head This commit looks good
2026-08-17 15:59:13 +00:00
ecda263518 ci: retry deployment with Jenkins SMTP secret mount
All checks were successful
Tests / Backend - Tests passed: 8
THE-TIP-TOP-MULTIBRANCH/pipeline/head This commit looks good
2026-08-17 15:30:55 +00:00
1f11a4e3dd ci: retry develop deployment after SMTP secret setup
Some checks failed
Tests / Backend - Tests passed: 8
THE-TIP-TOP-MULTIBRANCH/pipeline/head There was a failure building this commit
2026-08-17 15:24:50 +00:00
117ebac770 fix: configure SMTP and public API URLs for deployments
Some checks failed
Tests / Backend - Tests passed: 8
THE-TIP-TOP-MULTIBRANCH/pipeline/head There was a failure building this commit
2026-08-17 15:19:32 +00:00
d9d2eaba3d merge: promote validated develop to main 2026-08-17 14:55:36 +00:00
047d34f59b fix: resolve frontend lint issues
All checks were successful
Tests / Backend - Tests passed: 8
THE-TIP-TOP-MULTIBRANCH/pipeline/head This commit looks good
2026-08-17 14:54:58 +00:00
9 changed files with 97 additions and 96 deletions

View File

@@ -24,6 +24,9 @@ services:
image: ${REGISTRY}/the-tip-top/backend:${IMAGE_TAG}
restart: unless-stopped
env_file:
- /opt/furious-ducks/secrets/tiptop-mail.env
depends_on:
postgres:
condition: service_healthy
@@ -34,6 +37,7 @@ services:
DATABASE_URL: postgresql://tiptop:tiptop_dev_password@postgres:5432/the_tip_top_db
JWT_SECRET: dev_secret_change_me
APP_URL: https://api-dev.dsp5-archi-o24a-4-5-g4.fr
API_PUBLIC_URL: https://api-dev.dsp5-archi-o24a-4-5-g4.fr
command: >
sh -c "

View File

@@ -24,6 +24,9 @@ services:
image: ${REGISTRY}/the-tip-top/backend:${IMAGE_TAG}
restart: unless-stopped
env_file:
- /opt/furious-ducks/secrets/tiptop-mail.env
depends_on:
postgres:
condition: service_healthy
@@ -34,6 +37,7 @@ services:
DATABASE_URL: postgresql://tiptop_preprod:tiptop_preprod_password@postgres:5432/the_tip_top_preprod
JWT_SECRET: preprod_secret_change_me
APP_URL: https://api-preprod.dsp5-archi-o24a-4-5-g4.fr
API_PUBLIC_URL: https://api-preprod.dsp5-archi-o24a-4-5-g4.fr
command: >
sh -c "

View File

@@ -24,6 +24,9 @@ services:
image: ${REGISTRY}/the-tip-top/backend:${IMAGE_TAG}
restart: unless-stopped
env_file:
- /opt/furious-ducks/secrets/tiptop-mail.env
depends_on:
postgres:
condition: service_healthy
@@ -34,6 +37,7 @@ services:
DATABASE_URL: postgresql://tiptop_prod:tiptop_prod_password@postgres:5432/the_tip_top_prod
JWT_SECRET: prod_secret_change_me
APP_URL: https://api.dsp5-archi-o24a-4-5-g4.fr
API_PUBLIC_URL: https://api.dsp5-archi-o24a-4-5-g4.fr
command: >
sh -c "

View File

@@ -1,12 +1,7 @@
import { Link, useLocation } from 'react-router-dom'
import { useAuth } from '../context/AuthContext'
export default function Footer() {
const { pathname } = useLocation()
const { user } = useAuth()
const isLoggedIn = !!user
function FooterLink({ to, children, className=''}) {
function FooterLink({ to, children, className = '', pathname }) {
return pathname === to ? (
<span className={className}>{children}</span>
) : (
@@ -14,18 +9,25 @@ export default function Footer() {
{children}
</Link>
)
}
}
export default function Footer() {
const { pathname } = useLocation()
const { user } = useAuth()
const isLoggedIn = !!user
return (
<footer className="bg-[#006B6B] text-white">
{/* Partie principale */}
<div className="max-w-7xl mx-auto px-6 py-10 grid grid-cols-2 md:grid-cols-4 gap-8">
{/* Logo */}
<div>
<FooterLink to='/accueil'>
<FooterLink
to="/accueil"
pathname={pathname}
>
<h3 className="text-xl font-bold mb-3">
Thé Tip Top
</h3>
@@ -35,54 +37,51 @@ export default function Footer() {
Participez au jeu-concours Thé Tip Top et tentez de gagner
des lots gourmands autour du thé.
</p>
</div>
{/* Navigation */}
<div>
<h3 className="text-lg font-semibold mb-5">
Navigation
</h3>
<ul className="space-y-3 text-teal-100">
<li>
<FooterLink
to="/accueil"
pathname={pathname}
className="hover:text-white transition"
>
Accueil
</FooterLink>
</li>
<li>
<FooterLink
to="/regles-jeu"
pathname={pathname}
className="hover:text-white transition"
>
Règles du jeu
</FooterLink>
</li>
<li>
<FooterLink
to="/saisir-code-unique"
pathname={pathname}
className="hover:text-white transition"
>
Tester mon code
</FooterLink>
</li>
{ !isLoggedIn && (
{!isLoggedIn && (
<li>
<FooterLink
to="/inscription"
pathname={pathname}
className="hover:text-white transition"
>
Créer un compte
@@ -91,35 +90,30 @@ export default function Footer() {
)}
</ul>
</div>
{/* Informations légales */}
<div>
<h3 className="text-lg font-semibold mb-5">
Informations
</h3>
<ul className="space-y-3 text-teal-100">
<li>
<FooterLink
to="/mentions-legales"
pathname={pathname}
className="hover:text-white transition"
>
Mentions légales
</FooterLink>
</li>
<li>
<FooterLink
to="/confidentialite"
pathname={pathname}
className="hover:text-white transition"
>
Politique de confidentialité
@@ -129,6 +123,7 @@ export default function Footer() {
<li>
<FooterLink
to="/accessibilite"
pathname={pathname}
className="hover:text-white transition"
>
Accessibilité
@@ -138,16 +133,17 @@ export default function Footer() {
<li>
<FooterLink
to="/cgu"
pathname={pathname}
className="hover:text-white transition"
>
CGU
</FooterLink>
</li>
<li>
<FooterLink
to="/contact"
pathname={pathname}
className="hover:text-white transition"
>
Contact
@@ -157,6 +153,7 @@ export default function Footer() {
<li>
<FooterLink
to="/sitemap"
pathname={pathname}
className="hover:text-white transition"
>
Plan du site
@@ -164,15 +161,10 @@ export default function Footer() {
</li>
</ul>
</div>
{/* Contact */}
<div>
<h3 className="text-lg font-semibold mb-5">
Contact
</h3>
@@ -181,11 +173,17 @@ export default function Footer() {
Une question sur le jeu ?
</p>
<a href="tel:+33184802034" className="block mt-2 font-medium hover:text-teal-300">
<a
href="tel:+33184802034"
className="block mt-2 font-medium hover:text-teal-300"
>
01 84 80 20 34
</a>
<a href="mailto:contact@thetiptop.fr" className="inline-block mt-3 font-medium hover:text-teal-300">
<a
href="mailto:contact@thetiptop.fr"
className="inline-block mt-3 font-medium hover:text-teal-300"
>
contact@thetiptop.fr
</a>
@@ -194,22 +192,14 @@ export default function Footer() {
<br />
75011 Paris, France
</p>
</div>
</div>
{/* Barre basse */}
<div className="border-t border-teal-800">
<div className="max-w-7xl mx-auto px-6 py-5 flex flex-col md:flex-row justify-between items-center gap-3">
<p className="text-teal-200 text-sm text-center md:text-left">
© {new Date().getFullYear()} Thé Tip Top. Tous droits réservés.
<br className="md:hidden" />
@@ -219,6 +209,7 @@ export default function Footer() {
</p>
<div className="flex gap-5 text-sm text-teal-200">
<a
href="https://www.facebook.com/profile.php?id=61590449280854"
target="_blank"
@@ -228,7 +219,6 @@ export default function Footer() {
Facebook
</a>
<a
href="https://www.instagram.com/thetiptop.gp4?igsh=MXZ3YzZ0d3dkazBpeg%3D%3D&utm_source=qr"
target="_blank"
@@ -238,7 +228,6 @@ export default function Footer() {
Instagram
</a>
<a
href="https://www.tiktok.com/@thetiptop4"
target="_blank"
@@ -249,13 +238,9 @@ export default function Footer() {
</a>
</div>
</div>
</div>
</footer>
)
}

View File

@@ -1,3 +1,5 @@
/* eslint-disable react-refresh/only-export-components */
import { createContext, useContext, useState } from 'react'
const AuthContext = createContext(null)

View File

@@ -56,7 +56,7 @@ export default function Admin() {
if (!handleAuthError(e)) setError(e.message)
})
.finally(() => setLoading(false))
}, [])
}, [handleAuthError])
const handleDraw = async () => {
setShowConfirm(false)
@@ -94,7 +94,7 @@ export default function Admin() {
const csv = [header, ...rows]
.map((row) => row.map((cell) => `"${String(cell).replace(/"/g, '""')}"`).join(';'))
.join('\n')
const blob = new Blob([`${csv}`], { type: 'text/csv;charset=utf-8;' })
const blob = new Blob(['\uFEFF' + csv], { type: 'text/csv;charset=utf-8;' })
const url = URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url

View File

@@ -50,7 +50,20 @@ export default function MesGains() {
}
}, [handleAuthError])
useEffect(() => { fetchGains() }, [fetchGains])
useEffect(() => {
const loadGains = async () => {
try {
const data = await myGainsApi()
setGains(data.gains)
} catch (err) {
if (!handleAuthError(err)) setError(err.message)
} finally {
setLoading(false)
}
}
loadGains()
}, [handleAuthError])
return (
<div className="min-h-screen bg-gray-50 flex flex-col px-8 py-12 max-w-lg mx-auto">

View File

@@ -1,20 +1,12 @@
import { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import UserNav from '../components/UserNav'
import { changePasswordApi, deleteAccountApi } from '../services/auth'
import { changePasswordApi} from '../services/auth'
import { useHandleAuthError } from '../hooks/useHandleAuthError'
import { useAuth } from '../context/AuthContext'
export default function Profile() {
const user = JSON.parse(localStorage.getItem('user') || '{}')
const initials = `${(user.firstname || '?')[0]}${(user.lastname || '?')[0]}`.toUpperCase()
const handleAuthError = useHandleAuthError()
const { logout } = useAuth()
const navigate = useNavigate()
const [showDeleteModal, setShowDeleteModal] = useState(false)
const [deleting, setDeleting] = useState(false)
const [deleteError, setDeleteError] = useState('')
const [pwForm, setPwForm] = useState({ currentPassword: '', newPassword: '', confirmPassword: '' })
const [showPw, setShowPw] = useState({ current: false, new: false, confirm: false })

View File

@@ -17,7 +17,6 @@ export default function SaisirCodeUnique() {
const [code, setCode] = useState('')
const [loading, setLoading] = useState(false)
const [gain, setGain] = useState(null)
const [claim, setClaim] = useState(null)
const [wonAt, setWonAt] = useState(null)
const [showDetail, setShowDetail] = useState(false)
@@ -27,7 +26,6 @@ export default function SaisirCodeUnique() {
try {
const data = await participateApi(code.trim().toUpperCase())
setGain(data.gain)
setClaim(data.claim)
setWonAt(new Date())
} catch (err) {
if (!handleAuthError(err)) {
@@ -40,7 +38,6 @@ export default function SaisirCodeUnique() {
const handleClose = () => {
setGain(null)
setClaim(null)
setWonAt(null)
setShowDetail(false)
setCode('')