Compare commits
7 Commits
a572fa1a15
...
release-1.
| Author | SHA1 | Date | |
|---|---|---|---|
| bdcdf1a4da | |||
| 79e10946b8 | |||
| 79f463d280 | |||
| a09e9f17b5 | |||
| a40a62d600 | |||
| 12685c1b22 | |||
| 3a0dd25ed2 |
6
Jenkinsfile
vendored
6
Jenkinsfile
vendored
@@ -49,6 +49,7 @@ pipeline {
|
||||
env.DEPLOY_NETWORK = 'tiptop-dev'
|
||||
|
||||
env.FRONTEND_API_URL = "https://api-dev.dsp5-archi-o24a-4-5-g4.fr"
|
||||
env.FRONTEND_GA_ID = ""
|
||||
|
||||
} else if (env.BRANCH_NAME.startsWith('release-')) {
|
||||
env.DEPLOY_ENABLED = 'true'
|
||||
@@ -59,6 +60,7 @@ pipeline {
|
||||
env.DEPLOY_NETWORK = 'tiptop-preprod'
|
||||
|
||||
env.FRONTEND_API_URL = "https://api-preprod.dsp5-archi-o24a-4-5-g4.fr"
|
||||
env.FRONTEND_GA_ID = ""
|
||||
|
||||
} else if (env.BRANCH_NAME == 'main') {
|
||||
env.DEPLOY_ENABLED = 'true'
|
||||
@@ -69,6 +71,7 @@ pipeline {
|
||||
env.DEPLOY_NETWORK = 'tiptop-prod'
|
||||
|
||||
env.FRONTEND_API_URL = "https://api.dsp5-archi-o24a-4-5-g4.fr"
|
||||
env.FRONTEND_GA_ID = "G-4FTNTPJDRJ"
|
||||
|
||||
} else {
|
||||
env.DEPLOY_ENABLED = 'false'
|
||||
@@ -78,6 +81,7 @@ pipeline {
|
||||
env.COMPOSE_PROJECT = ''
|
||||
env.DEPLOY_NETWORK = ''
|
||||
env.FRONTEND_API_URL = ''
|
||||
env.FRONTEND_GA_ID = ""
|
||||
}
|
||||
|
||||
echo "Branche : ${env.BRANCH_NAME}"
|
||||
@@ -163,6 +167,7 @@ pipeline {
|
||||
npm ci --prefer-offline --no-audit --no-fund &&
|
||||
npx prisma generate &&
|
||||
npx prisma migrate deploy &&
|
||||
npx prisma db seed &&
|
||||
npm test
|
||||
"
|
||||
'''
|
||||
@@ -229,6 +234,7 @@ pipeline {
|
||||
|
||||
docker build \
|
||||
--build-arg VITE_API_URL="${FRONTEND_API_URL}" \
|
||||
--build-arg VITE_GA_ID="${FRONTEND_GA_ID}" \
|
||||
-t "${FRONTEND_IMAGE}:${IMAGE_TAG}" \
|
||||
frontend
|
||||
'''
|
||||
|
||||
@@ -36,25 +36,9 @@ services:
|
||||
NODE_ENV: development
|
||||
DATABASE_URL: postgresql://tiptop:tiptop_dev_password@postgres:5432/the_tip_top_db
|
||||
JWT_SECRET: dev_secret_change_me
|
||||
<<<<<<< HEAD
|
||||
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
|
||||
=======
|
||||
APP_URL: http://192.168.1.23:5001
|
||||
FRONTEND_URL: http://192.168.1.23:5173
|
||||
MAIL_HOST: smtp.gmail.com
|
||||
MAIL_PORT: 587
|
||||
MAIL_USER: ""
|
||||
MAIL_PASS: ""
|
||||
MAIL_FROM: "The Tip Top <no-reply@tiptop.local>"
|
||||
>>>>>>> github/Emmanuel
|
||||
|
||||
# Injectés par le pipeline, jamais commités. Vides, les routes de
|
||||
# connexion externe répondent 503 sans bloquer le démarrage.
|
||||
GOOGLE_CLIENT_ID: "${GOOGLE_CLIENT_ID:-}"
|
||||
GOOGLE_CLIENT_SECRET: "${GOOGLE_CLIENT_SECRET:-}"
|
||||
FACEBOOK_APP_ID: "${FACEBOOK_APP_ID:-}"
|
||||
FACEBOOK_APP_SECRET: "${FACEBOOK_APP_SECRET:-}"
|
||||
FRONTEND_URL: https://dev.dsp5-archi-o24a-4-5-g4.fr
|
||||
|
||||
command: >
|
||||
sh -c "
|
||||
|
||||
@@ -36,25 +36,9 @@ services:
|
||||
NODE_ENV: preproduction
|
||||
DATABASE_URL: postgresql://tiptop_preprod:tiptop_preprod_password@postgres:5432/the_tip_top_preprod
|
||||
JWT_SECRET: preprod_secret_change_me
|
||||
<<<<<<< HEAD
|
||||
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
|
||||
=======
|
||||
APP_URL: http://192.168.1.23:5002
|
||||
FRONTEND_URL: http://192.168.1.23:5174
|
||||
MAIL_HOST: smtp.gmail.com
|
||||
MAIL_PORT: 587
|
||||
MAIL_USER: ""
|
||||
MAIL_PASS: ""
|
||||
MAIL_FROM: "The Tip Top Preprod <no-reply@tiptop.local>"
|
||||
>>>>>>> github/Emmanuel
|
||||
|
||||
# Injectés par le pipeline, jamais commités. Vides, les routes de
|
||||
# connexion externe répondent 503 sans bloquer le démarrage.
|
||||
GOOGLE_CLIENT_ID: "${GOOGLE_CLIENT_ID:-}"
|
||||
GOOGLE_CLIENT_SECRET: "${GOOGLE_CLIENT_SECRET:-}"
|
||||
FACEBOOK_APP_ID: "${FACEBOOK_APP_ID:-}"
|
||||
FACEBOOK_APP_SECRET: "${FACEBOOK_APP_SECRET:-}"
|
||||
FRONTEND_URL: https://preprod.dsp5-archi-o24a-4-5-g4.fr
|
||||
|
||||
command: >
|
||||
sh -c "
|
||||
|
||||
@@ -36,26 +36,9 @@ services:
|
||||
NODE_ENV: production
|
||||
DATABASE_URL: postgresql://tiptop_prod:tiptop_prod_password@postgres:5432/the_tip_top_prod
|
||||
JWT_SECRET: prod_secret_change_me
|
||||
<<<<<<< HEAD
|
||||
APP_URL: https://api.dsp5-archi-o24a-4-5-g4.fr
|
||||
API_PUBLIC_URL: https://api.dsp5-archi-o24a-4-5-g4.fr
|
||||
=======
|
||||
APP_URL: http://192.168.1.23:5003
|
||||
FRONTEND_URL: http://192.168.1.23:5175
|
||||
|
||||
MAIL_HOST: smtp.gmail.com
|
||||
MAIL_PORT: 587
|
||||
MAIL_USER: ""
|
||||
MAIL_PASS: ""
|
||||
MAIL_FROM: "The Tip Top <no-reply@tiptop.local>"
|
||||
>>>>>>> github/Emmanuel
|
||||
|
||||
# Injectés par le pipeline, jamais commités. Vides, les routes de
|
||||
# connexion externe répondent 503 sans bloquer le démarrage.
|
||||
GOOGLE_CLIENT_ID: "${GOOGLE_CLIENT_ID:-}"
|
||||
GOOGLE_CLIENT_SECRET: "${GOOGLE_CLIENT_SECRET:-}"
|
||||
FACEBOOK_APP_ID: "${FACEBOOK_APP_ID:-}"
|
||||
FACEBOOK_APP_SECRET: "${FACEBOOK_APP_SECRET:-}"
|
||||
FRONTEND_URL: https://dsp5-archi-o24a-4-5-g4.fr
|
||||
|
||||
command: >
|
||||
sh -c "
|
||||
|
||||
@@ -8,7 +8,10 @@ RUN npm ci
|
||||
COPY . .
|
||||
|
||||
ARG VITE_API_URL
|
||||
ARG VITE_GA_ID
|
||||
|
||||
ENV VITE_API_URL=${VITE_API_URL}
|
||||
ENV VITE_GA_ID=${VITE_GA_ID}
|
||||
|
||||
RUN npm run build
|
||||
|
||||
|
||||
@@ -1,40 +1,78 @@
|
||||
import { useState } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Link, useLocation } from 'react-router-dom'
|
||||
import { initAnalytics, trackPageView } from '../services/analytics'
|
||||
|
||||
export default function CookieBanner() {
|
||||
const [visible, setVisible] = useState(() => !localStorage.getItem('cookieConsent'))
|
||||
const location = useLocation()
|
||||
|
||||
if (!visible) return null
|
||||
const [consent, setConsent] = useState(() =>
|
||||
localStorage.getItem('cookieConsent')
|
||||
)
|
||||
|
||||
const visible = consent === null
|
||||
|
||||
// Si le consentement avait déjà été donné lors d'une précédente visite,
|
||||
// Analytics est initialisé au chargement de l'application.
|
||||
useEffect(() => {
|
||||
if (consent !== 'accepted') return
|
||||
|
||||
initAnalytics()
|
||||
trackPageView(location.pathname + location.search)
|
||||
}, [consent, location.pathname, location.search])
|
||||
|
||||
const handleChoice = (choice) => {
|
||||
localStorage.setItem('cookieConsent', choice)
|
||||
setVisible(false)
|
||||
setConsent(choice)
|
||||
|
||||
if (choice === 'accepted') {
|
||||
initAnalytics()
|
||||
trackPageView(location.pathname + location.search)
|
||||
}
|
||||
}
|
||||
|
||||
if (!visible) return null
|
||||
|
||||
return (
|
||||
<div className="fixed bottom-0 left-0 right-0 z-50 px-4 py-4 bg-white border-t border-gray-200 shadow-lg">
|
||||
<div className="max-w-5xl mx-auto flex flex-col sm:flex-row items-start sm:items-center gap-4">
|
||||
|
||||
<div className="flex-1">
|
||||
<p className="text-sm font-semibold text-gray-800 mb-1">Ce site utilise des cookies</p>
|
||||
<p className="text-sm font-semibold text-gray-800 mb-1">
|
||||
Gestion des cookies
|
||||
</p>
|
||||
|
||||
<p className="text-xs text-gray-500 leading-relaxed">
|
||||
Nous utilisons des cookies essentiels au fonctionnement du site. En continuant votre navigation, vous acceptez leur utilisation conformément à notre{' '}
|
||||
<Link to="/confidentialite" className="text-[#006B6B] hover:underline">politique de confidentialité</Link>.
|
||||
Les cookies strictement nécessaires au fonctionnement du site sont
|
||||
utilisés automatiquement. Avec votre accord, nous utilisons également
|
||||
Google Analytics afin de mesurer l'audience et améliorer le site. Vous
|
||||
pouvez accepter ou refuser ces cookies statistiques. Consultez notre{' '}
|
||||
<Link
|
||||
to="/confidentialite"
|
||||
className="text-[#006B6B] hover:underline"
|
||||
>
|
||||
politique de confidentialité
|
||||
</Link>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 flex-shrink-0 w-full sm:w-auto">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleChoice('refused')}
|
||||
className="flex-1 sm:flex-none border border-gray-300 text-gray-600 hover:bg-gray-50 text-sm font-medium px-4 py-2.5 rounded-lg transition-colors"
|
||||
>
|
||||
Refuser
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleChoice('accepted')}
|
||||
className="flex-1 sm:flex-none bg-[#006B6B] hover:bg-[#005959] text-white text-sm font-medium px-4 py-2.5 rounded-lg transition-colors"
|
||||
>
|
||||
Accepter
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -17,9 +17,11 @@ export default function Connexion() {
|
||||
|
||||
// Navigation pleine page (et non fetch) : le flux OAuth passe par des
|
||||
// redirections vers Google puis retour sur /auth/callback.
|
||||
const handleGoogleLogin = () => {
|
||||
window.location.href = '/api/auth/google'
|
||||
}
|
||||
const API_URL = import.meta.env.VITE_API_URL || ''
|
||||
|
||||
const handleGoogleLogin = () => {
|
||||
window.location.href = `${API_URL}/api/auth/google`
|
||||
}
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault()
|
||||
|
||||
33
frontend/src/services/analytics.js
Normal file
33
frontend/src/services/analytics.js
Normal file
@@ -0,0 +1,33 @@
|
||||
const GA_ID = import.meta.env.VITE_GA_ID
|
||||
|
||||
export function initAnalytics() {
|
||||
if (!GA_ID || window.gtag) return
|
||||
|
||||
const script = document.createElement('script')
|
||||
script.async = true
|
||||
script.src = `https://www.googletagmanager.com/gtag/js?id=${GA_ID}`
|
||||
document.head.appendChild(script)
|
||||
|
||||
window.dataLayer = window.dataLayer || []
|
||||
|
||||
window.gtag = function gtag() {
|
||||
window.dataLayer.push(arguments)
|
||||
}
|
||||
|
||||
window.gtag('js', new Date())
|
||||
|
||||
// Les page_view sont envoyées explicitement lors des changements de route React.
|
||||
window.gtag('config', GA_ID, {
|
||||
send_page_view: false,
|
||||
})
|
||||
}
|
||||
|
||||
export function trackPageView(path) {
|
||||
if (!GA_ID || !window.gtag) return
|
||||
|
||||
window.gtag('event', 'page_view', {
|
||||
page_path: path,
|
||||
page_location: window.location.href,
|
||||
page_title: document.title,
|
||||
})
|
||||
}
|
||||
@@ -8,7 +8,7 @@ describe('CookieBanner', () => {
|
||||
it("s'affiche quand aucun choix n'a été fait", () => {
|
||||
renderWithProviders(<CookieBanner />)
|
||||
|
||||
expect(screen.getByText(/ce site utilise des cookies/i)).toBeInTheDocument()
|
||||
expect(screen.getByText(/gestion des cookies/i)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('enregistre le consentement et disparaît quand on accepte', async () => {
|
||||
|
||||
Reference in New Issue
Block a user