diff --git a/FencerJudgeFront/src/app/components/home/home.component.css b/FencerJudgeFront/src/app/components/home/home.component.css index 4e85ad9..ddf7d9e 100644 --- a/FencerJudgeFront/src/app/components/home/home.component.css +++ b/FencerJudgeFront/src/app/components/home/home.component.css @@ -1,560 +1,568 @@ .match-card { - background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); - border: 2px solid #daa520; - border-radius: 16px; - padding: 24px; - box-shadow: - 0 8px 32px rgba(0, 0, 0, 0.4), - inset 0 1px 0 rgba(255, 255, 255, 0.1); - position: relative; - overflow: hidden; - transition: all 0.3s ease; - height: 80vh; - width: 100%; + background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); + border: 2px solid #daa520; + padding: 24px; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4), + inset 0 1px 0 rgba(255, 255, 255, 0.1); + position: relative; + overflow: hidden; + transition: all 0.3s ease; + height: 80vh; + width: 100%; } .match-card::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 2px; - background: linear-gradient(90deg, #daa520, #ffd700, #daa520); - background-size: 200% 100%; - animation: gradientShift 15s ease infinite; + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 2px; + background: linear-gradient(90deg, #daa520, #ffd700, #daa520); + background-size: 200% 100%; + animation: gradientShift 15s ease infinite; } @keyframes gradientShift { - 0% { - background-position: 0% 50%; - } + 0% { + background-position: 0% 50%; + } - 50% { - background-position: 100% 50%; - } + 50% { + background-position: 100% 50%; + } - 100% { - background-position: 0% 50%; - } + 100% { + background-position: 0% 50%; + } } -.match-card:hover { - transform: translateY(-4px); - box-shadow: - 0 12px 48px rgba(218, 165, 32, 0.2), - 0 8px 32px rgba(0, 0, 0, 0.4); +.match-card { + transform: translateY(-4px); + box-shadow: 0 12px 48px rgba(218, 165, 32, 0.2), 0 8px 32px rgba(0, 0, 0, 0.4); } .match-background { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: -1; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: -1; } .background-image { - width: 100%; - height: 100%; - object-fit: cover; - filter: grayscale(30%) brightness(0.4) contrast(1.2); - transition: all 0.5s ease; + width: 100%; + height: 100%; + object-fit: cover; + filter: grayscale(30%) brightness(0.4) contrast(1.2); + transition: all 0.5s ease; } .match-card:hover .background-image { - filter: grayscale(10%) brightness(0.3) contrast(1.4); - transform: scale(1.05); + filter: grayscale(10%) brightness(0.3) contrast(1.4); + transform: scale(1.05); } .image-overlay { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: - linear-gradient(135deg, - rgba(26, 26, 46, 0.85) 0%, - rgba(0, 0, 0, 0.7) 50%, - rgba(22, 33, 62, 0.85) 100% - ); + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient( + 135deg, + rgba(26, 26, 46, 0.85) 0%, + rgba(0, 0, 0, 0.7) 50%, + rgba(22, 33, 62, 0.85) 100% + ); } /* Header */ .match-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 20px; + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; } .match-weapon { - display: flex; - align-items: center; - gap: 8px; - color: #daa520; - font-weight: 600; + display: flex; + align-items: center; + gap: 8px; + color: #daa520; + font-weight: 600; } .weapon-type { - font-size: 14px; - text-transform: uppercase; - letter-spacing: 1px; + font-size: 14px; + text-transform: uppercase; + letter-spacing: 1px; } /* Status */ .match-status { - display: flex; - align-items: center; - gap: 8px; - padding: 6px 12px; - border-radius: 20px; - font-size: 12px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.5px; + display: flex; + align-items: center; + gap: 8px; + padding: 6px 12px; + border-radius: 20px; + font-size: 12px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; } -.status-live { - background: rgba(34, 197, 94, 0.2); - color: #22c55e; - border: 1px solid #22c55e; +.status-warning { + background: rgba(34, 197, 94, 0.2); + color: #22c55e; + border: 1px solid #22c55e; } -.status-finished { - background: rgba(239, 68, 68, 0.2); - color: #ef4444; - border: 1px solid #ef4444; +.status-success { + background: rgba(239, 68, 68, 0.2); + color: #ef4444; + border: 1px solid #ef4444; } -.status-upcoming { - background: rgba(59, 130, 246, 0.2); - color: #3b82f6; - border: 1px solid #3b82f6; +.status-secondary { + background: rgba(59, 130, 246, 0.2); + color: #3b82f6; + border: 1px solid #3b82f6; } .status-dot { - width: 8px; - height: 8px; - border-radius: 50%; - background: currentColor; - animation: pulse 2s infinite; + width: 8px; + height: 8px; + border-radius: 50%; + background: currentColor; + animation: pulse 2s infinite; } @keyframes pulse { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.5; } + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0.5; + } } /* Versus Section */ .match-versus { - display: flex; - align-items: center; - justify-content: space-between; - margin: 24px 0; - position: relative; + display: flex; + align-items: center; + justify-content: space-between; + margin: 24px 0; + position: relative; } .fencer { - flex: 1; - text-align: center; - color: white; + flex: 1; + text-align: center; + color: white; } .fencer-name { - font-size: 18px; - font-weight: 700; - margin-bottom: 4px; - color: #daa520; + font-size: 18px; + font-weight: 700; + margin-bottom: 4px; + color: #daa520; } .fencer-club { - font-size: 12px; - color: #9ca3af; - margin-bottom: 8px; + font-size: 12px; + color: #9ca3af; + margin-bottom: 8px; } .score { - font-size: 32px; - font-weight: 900; - color: white; - text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5); + font-size: 32px; + font-weight: 900; + color: white; + text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5); } .vs-divider { - display: flex; - flex-direction: column; - align-items: center; - gap: 4px; - margin: 0 20px; + display: flex; + flex-direction: column; + align-items: center; + gap: 4px; + margin: 0 20px; } .vs-text { - font-size: 14px; - font-weight: 700; - color: #6b7280; - letter-spacing: 2px; + font-size: 14px; + font-weight: 700; + color: #6b7280; + letter-spacing: 2px; } .crossed-swords { - font-size: 20px; - opacity: 0.7; + font-size: 20px; + opacity: 0.7; } /* Details */ .match-details { - display: flex; - flex-direction: column; - gap: 12px; - margin-top: 20px; - padding-top: 20px; - border-top: 1px solid rgba(255, 255, 255, 0.1); + display: flex; + flex-direction: column; + gap: 12px; + margin-top: 20px; + padding-top: 20px; + border-top: 1px solid rgba(255, 255, 255, 0.1); } .detail-item { - display: flex; - align-items: center; - gap: 12px; - font-size: 14px; + display: flex; + align-items: center; + gap: 12px; + font-size: 14px; } .detail-item .icon { - font-size: 16px; - width: 20px; - text-align: center; + font-size: 16px; + width: 20px; + text-align: center; } .detail-item .label { - color: #9ca3af; - font-weight: 500; - min-width: 60px; + color: #9ca3af; + font-weight: 500; + min-width: 60px; } .detail-item .value { - color: white; - font-weight: 600; + color: white; + font-weight: 600; } /* Responsive */ @media (max-width: 768px) { - .match-card { - padding: 16px; - } - - .match-versus { - flex-direction: column; - gap: 16px; - } - - .vs-divider { - transform: rotate(90deg); - margin: 0; - } - - .fencer { - width: 100%; - } + .match-card { + padding: 16px; + } + + .match-versus { + flex-direction: column; + gap: 16px; + } + + .vs-divider { + transform: rotate(90deg); + margin: 0; + } + + .fencer { + width: 100%; + } } .combat-arena { - margin-top: 24px; - background: - linear-gradient(135deg, - rgba(220, 38, 38, 0.1) 0%, - rgba(0, 0, 0, 0.8) 50%, - rgba(255, 215, 0, 0.1) 100% - ); - border: 2px solid; - border-image: linear-gradient(45deg, #dc2626, #ffd700, #dc2626) 1; - border-radius: 12px; - padding: 20px; - position: relative; - overflow: hidden; + margin-top: 24px; + background: linear-gradient( + 135deg, + rgba(220, 38, 38, 0.1) 0%, + rgba(0, 0, 0, 0.8) 50%, + rgba(255, 215, 0, 0.1) 100% + ); + border: 2px solid; + border-image: linear-gradient(45deg, #dc2626, #ffd700, #dc2626) 1; + border-radius: 12px; + padding: 20px; + position: relative; + overflow: hidden; } .combat-arena::before { - content: ''; - position: absolute; - top: -50%; - left: -50%; - width: 200%; - height: 200%; - background: - repeating-conic-gradient( - from 0deg at 50% 50%, - transparent 0deg 2deg, - rgba(220, 38, 38, 0.05) 2deg 4deg - ); - animation: rotate 20s linear infinite; - pointer-events: none; + content: ""; + position: absolute; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: repeating-conic-gradient( + from 0deg at 50% 50%, + transparent 0deg 2deg, + rgba(220, 38, 38, 0.05) 2deg 4deg + ); + animation: rotate 20s linear infinite; + pointer-events: none; } @keyframes rotate { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } } /* Header Arena */ .arena-header { - display: flex; - align-items: center; - justify-content: center; - gap: 12px; - margin-bottom: 20px; - position: relative; + display: flex; + align-items: center; + justify-content: center; + gap: 12px; + margin-bottom: 20px; + position: relative; } .arena-title { - font-family: 'Orbitron', monospace; - font-size: 16px; - font-weight: 900; - color: #ffd700; - letter-spacing: 3px; - text-shadow: - 0 0 10px #ffd700, - 0 0 20px #ffd700, - 0 0 30px #ffd700; - animation: titleGlow 2s ease-in-out infinite alternate; + font-family: "Orbitron", monospace; + font-size: 16px; + font-weight: 900; + color: #ffd700; + letter-spacing: 3px; + text-shadow: 0 0 10px #ffd700, 0 0 20px #ffd700, 0 0 30px #ffd700; + animation: titleGlow 2s ease-in-out infinite alternate; } @keyframes titleGlow { - from { text-shadow: 0 0 10px #ffd700, 0 0 20px #ffd700, 0 0 30px #ffd700; } - to { text-shadow: 0 0 20px #ffd700, 0 0 30px #ffd700, 0 0 40px #ffd700; } + from { + text-shadow: 0 0 10px #ffd700, 0 0 20px #ffd700, 0 0 30px #ffd700; + } + to { + text-shadow: 0 0 20px #ffd700, 0 0 30px #ffd700, 0 0 40px #ffd700; + } } .arena-pulse { - width: 10px; - height: 10px; - background: #dc2626; - border-radius: 50%; - position: relative; - animation: pulse-danger 1s infinite; + width: 10px; + height: 10px; + background: #dc2626; + border-radius: 50%; + position: relative; + animation: pulse-danger 1s infinite; } .arena-pulse::before { - content: ''; - position: absolute; - top: -5px; - left: -5px; - right: -5px; - bottom: -5px; - background: #dc2626; - border-radius: 50%; - opacity: 0.3; - animation: pulse-ring 1s infinite; + content: ""; + position: absolute; + top: -5px; + left: -5px; + right: -5px; + bottom: -5px; + background: #dc2626; + border-radius: 50%; + opacity: 0.3; + animation: pulse-ring 1s infinite; } @keyframes pulse-danger { - 0%, 100% { transform: scale(1); } - 50% { transform: scale(1.2); } + 0%, + 100% { + transform: scale(1); + } + 50% { + transform: scale(1.2); + } } @keyframes pulse-ring { - 0% { transform: scale(0.8); opacity: 0.8; } - 100% { transform: scale(2); opacity: 0; } + 0% { + transform: scale(0.8); + opacity: 0.8; + } + 100% { + transform: scale(2); + opacity: 0; + } } /* Combat Grid */ .combat-grid { - display: grid; - grid-template-columns: 1fr; - gap: 16px; + display: grid; + grid-template-columns: 1fr; + gap: 16px; } .combat-stat { - display: flex; - align-items: center; - gap: 16px; - padding: 16px; - background: - linear-gradient(90deg, - rgba(0, 0, 0, 0.8) 0%, - rgba(26, 26, 46, 0.9) 50%, - rgba(0, 0, 0, 0.8) 100% - ); - border: 1px solid rgba(255, 215, 0, 0.3); - border-radius: 8px; - position: relative; - transition: all 0.3s ease; - cursor: pointer; + display: flex; + align-items: center; + gap: 16px; + padding: 16px; + background: linear-gradient( + 90deg, + rgba(0, 0, 0, 0.8) 0%, + rgba(26, 26, 46, 0.9) 50%, + rgba(0, 0, 0, 0.8) 100% + ); + border: 1px solid rgba(255, 215, 0, 0.3); + border-radius: 8px; + position: relative; + transition: all 0.3s ease; + cursor: pointer; } .combat-stat:hover { - transform: translateX(8px); - border-color: #ffd700; - box-shadow: - 0 4px 20px rgba(255, 215, 0, 0.3), - inset 0 1px 0 rgba(255, 215, 0, 0.1); + transform: translateX(8px); + border-color: #ffd700; + box-shadow: 0 4px 20px rgba(255, 215, 0, 0.3), + inset 0 1px 0 rgba(255, 215, 0, 0.1); } /* Icons animés */ .stat-icon { - position: relative; - display: flex; - align-items: center; - justify-content: center; - width: 48px; - height: 48px; - font-size: 24px; + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 48px; + height: 48px; + font-size: 24px; } .location-radar { - position: absolute; - width: 40px; - height: 40px; - border: 2px solid #10b981; - border-radius: 50%; - border-top-color: transparent; - animation: radar-spin 2s linear infinite; + position: absolute; + width: 40px; + height: 40px; + border: 2px solid #10b981; + border-radius: 50%; + border-top-color: transparent; + animation: radar-spin 2s linear infinite; } .referee-badge { - position: absolute; - width: 35px; - height: 35px; - background: linear-gradient(45deg, #ffd700, #ffed4a); - clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%); - animation: badge-pulse 3s ease-in-out infinite; + position: absolute; + width: 35px; + height: 35px; + background: linear-gradient(45deg, #ffd700, #ffed4a); + clip-path: polygon( + 50% 0%, + 61% 35%, + 98% 35%, + 68% 57%, + 79% 91%, + 50% 70%, + 21% 91%, + 32% 57%, + 2% 35%, + 39% 35% + ); + animation: badge-pulse 3s ease-in-out infinite; } .time-ring { - position: absolute; - width: 36px; - height: 36px; - border: 3px solid #dc2626; - border-radius: 50%; - border-left-color: transparent; - animation: time-tick 1s linear infinite; + position: absolute; + width: 36px; + height: 36px; + border: 3px solid #dc2626; + border-radius: 50%; + border-left-color: transparent; + animation: time-tick 1s linear infinite; } @keyframes radar-spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } } @keyframes badge-pulse { - 0%, 100% { transform: scale(1) rotate(0deg); } - 50% { transform: scale(1.1) rotate(5deg); } + 0%, + 100% { + transform: scale(1) rotate(0deg); + } + 50% { + transform: scale(1.1) rotate(5deg); + } } @keyframes time-tick { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } } /* Content */ .stat-content { - flex: 1; - display: flex; - flex-direction: column; - gap: 2px; + flex: 1; + display: flex; + flex-direction: column; + gap: 2px; } .stat-label { - font-family: 'Orbitron', monospace; - font-size: 10px; - font-weight: 700; - color: #6b7280; - letter-spacing: 1px; - text-transform: uppercase; + font-family: "Orbitron", monospace; + font-size: 10px; + font-weight: 700; + color: #6b7280; + letter-spacing: 1px; + text-transform: uppercase; } .stat-value { - font-size: 16px; - font-weight: 700; - color: #ffffff; - text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); + font-size: 16px; + font-weight: 700; + color: #ffffff; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); } .stat-sub { - font-size: 11px; - color: #9ca3af; - font-weight: 500; + font-size: 11px; + color: #9ca3af; + font-weight: 500; } /* Glows spécifiques */ -.venue .stat-value { color: #10b981; } -.referee .stat-value { color: #ffd700; } -.timing .stat-value { color: #dc2626; } +.venue .stat-value { + color: #10b981; +} +.referee .stat-value { + color: #ffd700; +} +.timing .stat-value { + color: #dc2626; +} .stat-glow { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - border-radius: 8px; - opacity: 0; - transition: opacity 0.3s ease; - pointer-events: none; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + border-radius: 8px; + opacity: 0; + transition: opacity 0.3s ease; + pointer-events: none; } .combat-stat:hover .stat-glow { - opacity: 1; + opacity: 1; } -.venue-glow { box-shadow: inset 0 0 20px rgba(16, 185, 129, 0.2); } -.referee-glow { box-shadow: inset 0 0 20px rgba(255, 215, 0, 0.2); } -.timing-glow { box-shadow: inset 0 0 20px rgba(220, 38, 38, 0.2); } - -/* Footer Arena */ -.arena-footer { - margin-top: 20px; - display: flex; - align-items: center; - justify-content: center; - gap: 12px; +.venue-glow { + box-shadow: inset 0 0 20px rgba(16, 185, 129, 0.2); } - -.danger-tape { - flex: 1; - height: 4px; - background: - repeating-linear-gradient( - 45deg, - #ffd700 0px, - #ffd700 10px, - #dc2626 10px, - #dc2626 20px - ); - animation: tape-move 2s linear infinite; +.referee-glow { + box-shadow: inset 0 0 20px rgba(255, 215, 0, 0.2); } - -@keyframes tape-move { - 0% { background-position: 0px 0px; } - 100% { background-position: 28px 0px; } -} - -.warning-text { - font-family: 'Orbitron', monospace; - font-size: 12px; - font-weight: 700; - color: #ffd700; - letter-spacing: 1px; - animation: warning-blink 1.5s ease-in-out infinite alternate; -} - -@keyframes warning-blink { - 0% { opacity: 1; } - 100% { opacity: 0.6; } +.timing-glow { + box-shadow: inset 0 0 20px rgba(220, 38, 38, 0.2); } /* Responsive */ @media (min-width: 768px) { - .combat-grid { - grid-template-columns: repeat(3, 1fr); - } - - .combat-stat { - flex-direction: column; - text-align: center; - gap: 12px; - } - - .combat-stat:hover { - transform: translateY(-4px); - } -} + .combat-grid { + grid-template-columns: repeat(3, 1fr); + } + .combat-stat { + flex-direction: column; + text-align: center; + gap: 12px; + } + + .combat-stat:hover { + transform: translateY(-4px); + } +} diff --git a/FencerJudgeFront/src/app/components/home/home.component.html b/FencerJudgeFront/src/app/components/home/home.component.html index 402f9ff..37d0ba6 100644 --- a/FencerJudgeFront/src/app/components/home/home.component.html +++ b/FencerJudgeFront/src/app/components/home/home.component.html @@ -1,91 +1,114 @@ -
-
- Escrime -
+
+
+ Escrime +
+
+ +
+
+ ⚔️ + {{ latestMatch.weapon }} +
+
+ + {{ getMatchStateLabel(latestMatch.state) }} +
+
+ +
+
+
+ {{ player1?.name }} {{ player1?.firstName }} +
+
{{ player1?.club }}
+
{{ latestMatch.score1 }}
-
-
- ⚔️ - Épée -
-
- - En cours -
+
+ VS +
⚔️
-
-
-
Martin DUBOIS
-
CE Paris
-
12
-
+
+
+ {{ player2?.name }} {{ player2?.firstName }} +
+
{{ player2?.club }}
+
{{ latestMatch.score2 }}
+
+
-
- VS -
⚔️
-
- -
-
Sophie BERNARD
-
Escrime Lyon
-
8
-
+
+
+ ARENA COMBAT +
-
-
- ARENA COMBAT -
+
+
+
+
+ 🏛️
- -
-
-
-
- 🏛️ -
-
- BATTLEFIELD - Gymnase Jean Moulin - PARIS • ZONE A -
-
-
- -
-
-
- ⚖️ -
-
- COMBAT JUDGE - Pierre MARTIN - OFFICIAL REFEREE -
-
-
- -
-
-
- -
-
- COMBAT START - 14:30 - LIVE BATTLE -
-
-
+
+ BATTLEFIELD + {{ latestMatch.city }} + {{ latestMatch.country }}
+
+
- +
- \ No newline at end of file + diff --git a/FencerJudgeFront/src/app/components/home/home.component.ts b/FencerJudgeFront/src/app/components/home/home.component.ts index 67af68d..c6a3439 100644 --- a/FencerJudgeFront/src/app/components/home/home.component.ts +++ b/FencerJudgeFront/src/app/components/home/home.component.ts @@ -1,9 +1,159 @@ import { Component } from '@angular/core'; +import { MatchesService } from '@services/matches/matches.service'; +import { Matches, MatchState } from '@interfaces/matches'; + +import { PlayerService } from '@services/player/player.service'; +import { Player } from '@interfaces/player'; + +import { RefereeService } from '@services/referee/referee.service'; +import { Referee, RefereeLevel } from '@interfaces/referee'; + @Component({ selector: 'app-home', standalone: false, templateUrl: './home.component.html', styleUrl: './home.component.css', }) -export class HomeComponent {} +export class HomeComponent { + latestMatch?: Matches; + player1?: Player; + player2?: Player; + referee?: Referee; + MatchState = MatchState; + intervalId?: any; + timeUntilMatch: string | null = null; + + constructor( + private matchesService: MatchesService, + private playerService: PlayerService, + private refereeService: RefereeService + ) {} + + ngOnInit(): void { + this.getLatestMatch(); + } + + ngOnDestroy(): void { + if (this.intervalId) { + clearInterval(this.intervalId); + } + } + + private getLatestMatch(): void { + this.matchesService.getMatches().subscribe((matches) => { + if (matches.length > 0) { + this.latestMatch = matches[matches.length - 1]; + console.log( + '[HomeComponent] 🏁 Dernier match ajouté :', + this.latestMatch + ); + + // Récupération des données liées + this.loadRelatedEntities(this.latestMatch); + + if (this.latestMatch.state === MatchState.NOT_STARTED) { + this.updateTimeUntilMatch(); // initial + this.intervalId = setInterval(() => { + this.updateTimeUntilMatch(); + }, 60000); // chaque minute + } + } else { + console.warn('[HomeComponent] Aucun match disponible'); + } + }); + } + + private updateTimeUntilMatch(): void { + if (!this.latestMatch) return; + + const now = new Date(); + const matchDate = new Date(this.latestMatch.date); + const diffMs = matchDate.getTime() - now.getTime(); + + if (diffMs <= 0) { + this.timeUntilMatch = null; + clearInterval(this.intervalId); + return; + } + + const totalMinutes = Math.floor(diffMs / (1000 * 60)); + const days = Math.floor(totalMinutes / (60 * 24)); + const hours = Math.floor((totalMinutes % (60 * 24)) / 60); + const minutes = totalMinutes % 60; + + let result = ''; + if (days > 0) result += `${days}j `; + if (hours > 0 || days > 0) result += `${hours}h `; + result += `${minutes}min`; + + this.timeUntilMatch = result.trim(); + } + + private loadRelatedEntities(match: Matches): void { + this.playerService.getPlayerById(match.player1ID).subscribe((p1) => { + this.player1 = p1!; + }); + + this.playerService.getPlayerById(match.player2ID).subscribe((p2) => { + this.player2 = p2!; + }); + + this.refereeService.getRefereeById(match.refereeID).subscribe((ref) => { + this.referee = ref!; + }); + } + + getMatchStateLabel(state: MatchState): string { + switch (state) { + case MatchState.NOT_STARTED: + return 'À venir'; + case MatchState.ONGOING: + return 'En cours'; + case MatchState.OVER: + return 'Terminé'; + default: + return 'Inconnu'; + } + } + + getMatchStateColor(state: MatchState): string { + switch (state) { + case MatchState.NOT_STARTED: + return 'secondary'; + case MatchState.ONGOING: + return 'warning'; + case MatchState.OVER: + return 'success'; + default: + return 'light'; + } + } + + getTimeUntilMatch(): string | null { + if ( + !this.latestMatch || + this.latestMatch.state !== MatchState.NOT_STARTED + ) { + return null; + } + + const now = new Date(); + const matchDate = new Date(this.latestMatch.date); + const diffMs = matchDate.getTime() - now.getTime(); + + if (diffMs <= 0) return null; + + const totalMinutes = Math.floor(diffMs / (1000 * 60)); + const days = Math.floor(totalMinutes / (60 * 24)); + const hours = Math.floor((totalMinutes % (60 * 24)) / 60); + const minutes = totalMinutes % 60; + + let result = ''; + if (days > 0) result += `${days}j `; + if (hours > 0 || days > 0) result += `${hours}h `; + result += `${minutes}min`; + + return result.trim(); + } +} diff --git a/FencerJudgeFront/src/app/components/match/matches-add/matches-add.component.css b/FencerJudgeFront/src/app/components/match/matches-add/matches-add.component.css index e69de29..bb537a4 100644 --- a/FencerJudgeFront/src/app/components/match/matches-add/matches-add.component.css +++ b/FencerJudgeFront/src/app/components/match/matches-add/matches-add.component.css @@ -0,0 +1,18 @@ +form fieldset { + background-color: #f8f9fa; /* gris clair */ +} + +form legend { + font-weight: 600; + font-size: 1.1rem; +} + +form label { + font-weight: 500; +} + +form button { + width: 100%; + padding: 0.6rem; + font-size: 1.1rem; +} diff --git a/FencerJudgeFront/src/app/components/match/matches-add/matches-add.component.html b/FencerJudgeFront/src/app/components/match/matches-add/matches-add.component.html index 0e64f71..130f2cc 100644 --- a/FencerJudgeFront/src/app/components/match/matches-add/matches-add.component.html +++ b/FencerJudgeFront/src/app/components/match/matches-add/matches-add.component.html @@ -1,102 +1,171 @@ -

Ajouter un match

+

Ajouter un match

-
-
- Joueur 1 - - + +
+ Joueur 1 - - +
+ + +
- - +
+ + +
+ +
+ + +
-
- Joueur 2 - - +
+ Joueur 2 - - +
+ + +
- - +
+ + +
+ +
+ + +
-
- Arbitre - - +
+ Arbitre - - +
+ + +
- - +
+ + +
+ +
+ + +
-
- Match - - +
+ Match - - +
+ + +
- - +
+ + +
+ +
+ + +
+ +
+ + +
- + diff --git a/FencerJudgeFront/src/app/components/match/matches-add/matches-add.component.ts b/FencerJudgeFront/src/app/components/match/matches-add/matches-add.component.ts index b0acd38..77a8a94 100644 --- a/FencerJudgeFront/src/app/components/match/matches-add/matches-add.component.ts +++ b/FencerJudgeFront/src/app/components/match/matches-add/matches-add.component.ts @@ -36,6 +36,7 @@ export class MatchesAddComponent { city: '', country: '', weapon: '', + date: '', }; constructor( @@ -82,7 +83,7 @@ export class MatchesAddComponent { country: this.formData.country, city: this.formData.city, weapon: this.formData.weapon, - date: new Date(), + date: new Date(this.formData.date), state: MatchState.NOT_STARTED, }; diff --git a/FencerJudgeFront/src/app/components/match/matches-id/matches-id.component.ts b/FencerJudgeFront/src/app/components/match/matches-id/matches-id.component.ts index 7430beb..c0ff55a 100644 --- a/FencerJudgeFront/src/app/components/match/matches-id/matches-id.component.ts +++ b/FencerJudgeFront/src/app/components/match/matches-id/matches-id.component.ts @@ -11,6 +11,8 @@ import { Player } from '@interfaces/player'; import { RefereeService } from '@services/referee/referee.service'; import { Referee, RefereeLevel } from '@interfaces/referee'; +import { getMatchStateLabel, getMatchStateColor } from '@utils/getState'; + @Component({ selector: 'app-matches-id', standalone: false, diff --git a/FencerJudgeFront/src/app/utils/getState.ts b/FencerJudgeFront/src/app/utils/getState.ts new file mode 100644 index 0000000..c7f141d --- /dev/null +++ b/FencerJudgeFront/src/app/utils/getState.ts @@ -0,0 +1,27 @@ +import { MatchState } from '@interfaces/matches'; + +export function getMatchStateLabel(state: MatchState): string { + switch (state) { + case MatchState.NOT_STARTED: + return 'À venir'; + case MatchState.ONGOING: + return 'En cours'; + case MatchState.OVER: + return 'Terminé'; + default: + return 'Inconnu'; + } +} + +export function getMatchStateColor(state: MatchState): string { + switch (state) { + case MatchState.NOT_STARTED: + return 'secondary'; + case MatchState.ONGOING: + return 'warning'; + case MatchState.OVER: + return 'success'; + default: + return 'light'; + } +}