fix+feat(everything): lot of things
Some checks failed
Deploy to Development / build-and-deploy (push) Failing after 20s

This commit is contained in:
EvanChal
2026-01-25 22:14:48 +01:00
parent 5bbe05000e
commit dfeaecce73
15 changed files with 871 additions and 43 deletions

View File

@@ -1,15 +1,67 @@
FROM node:18-alpine
# Stage 1 : Build prod
FROM node:20-alpine AS builder
WORKDIR /app
# Copy package files first for better caching
COPY package*.json ./
# Install dependencies
RUN npm ci
# Copy application files
COPY . .
# Run the application in development mode
CMD ["npm", "run", "dev"]
ARG VITE_API_URL=https://api.lediscord.com
ARG VITE_APP_URL=https://lediscord.com
ARG VITE_UPLOAD_URL=https://api.lediscord.com/uploads
ENV VITE_API_URL=$VITE_API_URL
ENV VITE_APP_URL=$VITE_APP_URL
ENV VITE_UPLOAD_URL=$VITE_UPLOAD_URL
RUN npm run build
# Stage 2 : Image finale avec les deux modes
FROM node:20-alpine
RUN apk add --no-cache nginx
WORKDIR /app
# Copier les sources pour le mode dev
COPY package*.json ./
RUN npm ci
COPY . .
# Copier le build prod
COPY --from=builder /app/dist /usr/share/nginx/html
# Config nginx
RUN echo 'server { \
listen 8080; \
root /usr/share/nginx/html; \
index index.html; \
location / { \
try_files $uri $uri/ /index.html; \
} \
location /assets { \
expires 1y; \
add_header Cache-Control "public, immutable"; \
} \
}' > /etc/nginx/conf.d/default.conf
# Script d'entrée
COPY <<EOF /entrypoint.sh
#!/bin/sh
if [ "\$MODE" = "dev" ]; then
echo "🔧 Mode DEVELOPPEMENT"
exec npm run dev -- --host 0.0.0.0 --port 8080
else
echo "🚀 Mode PRODUCTION"
exec nginx -g "daemon off;"
fi
EOF
RUN chmod +x /entrypoint.sh
EXPOSE 8080
CMD ["/entrypoint.sh"]

View File

@@ -1,5 +1,5 @@
<template>
<div class="video-player-container">
<div class="video-player-container px-2 sm:px-0">
<div class="relative">
<!-- Video.js Player -->
<div data-vjs-player>

View File

@@ -71,7 +71,14 @@
</div>
<!-- Participation Badge -->
<div class="absolute top-2 right-2">
<div class="absolute top-2 right-2 flex gap-1">
<span
v-if="event.is_private"
class="px-2 py-1 rounded-full text-xs font-medium text-white bg-purple-600"
title="Événement privé"
>
🔒 Privé
</span>
<span
v-if="getUserParticipation(event)"
class="px-2 py-1 rounded-full text-xs font-medium text-white"
@@ -235,6 +242,68 @@
</div>
</div>
<!-- Type d'événement -->
<div>
<label class="label">Type d'événement</label>
<div class="flex gap-4">
<label class="flex items-center cursor-pointer">
<input
type="radio"
v-model="newEvent.is_private"
:value="false"
class="mr-2"
>
<span class="text-sm">Public (visible par tous)</span>
</label>
<label class="flex items-center cursor-pointer">
<input
type="radio"
v-model="newEvent.is_private"
:value="true"
class="mr-2"
>
<span class="text-sm">Privé (invitations uniquement)</span>
</label>
</div>
</div>
<!-- Sélection des invités pour événements privés -->
<div v-if="newEvent.is_private">
<label class="label">Inviter des membres</label>
<div class="border border-gray-300 rounded-lg p-3 max-h-48 overflow-y-auto">
<div
v-for="user in users.filter(u => u.id !== authStore.user?.id)"
:key="user.id"
class="flex items-center justify-between py-2 border-b border-gray-100 last:border-b-0"
>
<div class="flex items-center">
<img
v-if="user.avatar_url"
:src="getMediaUrl(user.avatar_url)"
:alt="user.full_name"
class="w-8 h-8 rounded-full mr-2 object-cover"
>
<div v-else class="w-8 h-8 rounded-full bg-primary-100 flex items-center justify-center mr-2">
<User class="w-4 h-4 text-primary-600" />
</div>
<div>
<div class="text-sm font-medium text-gray-900">{{ user.full_name }}</div>
<div class="text-xs text-gray-500">@{{ user.username }}</div>
</div>
</div>
<input
type="checkbox"
:value="user.id"
v-model="newEvent.invited_user_ids"
class="w-4 h-4 text-primary-600 rounded focus:ring-primary-500"
>
</div>
</div>
<p class="text-xs text-gray-500 mt-2">
Sélectionnez les membres à inviter à cet événement privé
</p>
</div>
<div class="flex gap-3 pt-4">
<button
type="button"
@@ -294,7 +363,9 @@ const newEvent = ref({
description: '',
date: '',
location: '',
end_date: null
end_date: null,
is_private: false,
invited_user_ids: []
})
const eventMentions = ref([])
@@ -399,6 +470,12 @@ async function quickParticipation(eventId, status) {
async function createEvent() {
if (!newEvent.value.title || !newEvent.value.date) return
// Vérifier que des invités sont sélectionnés pour les événements privés
if (newEvent.value.is_private && (!newEvent.value.invited_user_ids || newEvent.value.invited_user_ids.length === 0)) {
toast.warning('Veuillez sélectionner au moins un membre à inviter pour un événement privé')
return
}
creating.value = true
try {
const eventData = {
@@ -406,7 +483,9 @@ async function createEvent() {
description: newEvent.value.description,
date: new Date(newEvent.value.date).toISOString(),
location: newEvent.value.location,
end_date: newEvent.value.end_date ? new Date(newEvent.value.end_date).toISOString() : null
end_date: newEvent.value.end_date ? new Date(newEvent.value.end_date).toISOString() : null,
is_private: newEvent.value.is_private,
invited_user_ids: newEvent.value.is_private ? newEvent.value.invited_user_ids : null
}
await axios.post('/api/events', eventData)
@@ -416,7 +495,7 @@ async function createEvent() {
showCreateModal.value = false
resetForm()
toast.success('Événement créé avec succès')
toast.success(newEvent.value.is_private ? 'Événement privé créé avec succès' : 'Événement créé avec succès')
} catch (error) {
toast.error('Erreur lors de la création de l\'événement')
}
@@ -429,7 +508,9 @@ function resetForm() {
description: '',
date: '',
location: '',
end_date: null
end_date: null,
is_private: false,
invited_user_ids: []
}
}