diff --git a/code-challenge/src/App.css b/code-challenge/src/App.css index 27781fd9b..7873d5bec 100644 --- a/code-challenge/src/App.css +++ b/code-challenge/src/App.css @@ -1,8 +1,483 @@ + + +:root { + --primary: #2563eb; + --primary-dark: #1d4ed8; + --secondary: #4f46e5; + --accent: #0ea5e9; + --background: #f8fafc; + --card-bg: #ffffff; + --text-primary: #1e293b; + --text-secondary: #475569; + --border: #e2e8f0; + --success: #059669; + --error: #dc2626; +} + .App { text-align: center; - max-width: 800px; - margin: 0 auto; - padding: 20px; + width: 100%; + margin: 0px; + padding: 0px; + min-height: 100vh; + background: var(--background); + background-image: + radial-gradient(at 0% 0%, rgba(var(--primary-rgb), 0.03) 0px, transparent 50%), + radial-gradient(at 100% 0%, rgba(var(--secondary-rgb), 0.03) 0px, transparent 50%); + display: flex; + flex-direction: column; + align-items: center; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; +} + +.match-rating { + /* Container styles */ + background: var(--card-bg); + border-radius: 24px; + box-shadow: + 0 4px 6px -1px rgba(0, 0, 0, 0.1), + 0 2px 4px -1px rgba(0, 0, 0, 0.06); + padding: 32px 28px; + margin: 32px auto; + display: flex; + flex-direction: column; + align-items: stretch; + border: 1px solid var(--border); + width: 30rem; + transition: all 0.3s ease; +} + +/* Hover effects */ +.match-rating:hover { + transform: translateY(-2px); + box-shadow: + 0 10px 15px -3px rgba(0, 0, 0, 0.1), + 0 4px 6px -2px rgba(0, 0, 0, 0.05); +} + +/* Heading styles */ +.match-rating h2 { + font-family: 'Plus Jakarta Sans', sans-serif; + font-size: 1.75em; + margin-bottom: 28px; + color: var(--text-primary); + font-weight: 700; + letter-spacing: -0.025em; + background: linear-gradient(to right, var(--primary), var(--secondary)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; +} + +.form-group { + margin-bottom: 22px; + text-align: left; +} + +label { + display: block; + margin-bottom: 10px; + font-size: 1.05em; + color: #4b3f72; + font-weight: 500; +} + +select, input[type="range"] { + border-radius: 12px; + border: 1px solid var(--border); + font-size: 1em; + background: var(--background); + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); + font-family: 'Inter', sans-serif; +} + +select { + width: 100%; + padding: 12px 16px; + margin-bottom: 2px; + color: var(--text-primary); + font-weight: 500; + outline: none; + transition: all 0.2s ease; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%234b5563'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E"); + background-position: right 12px center; + background-repeat: no-repeat; + background-size: 16px; + padding-right: 40px; + appearance: none; + cursor: pointer; +} + +select:hover { + border-color: var(--primary); + background-color: var(--card-bg); +} + +select:focus { + border-color: var(--primary); + box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1); + background-color: var(--card-bg); +} + +input[type="range"] { + width: 100%; + height: 6px; + border-radius: 6px; + background: linear-gradient(to right, var(--primary) var(--value, 50%), var(--border) var(--value, 50%)); + outline: none; + -webkit-appearance: none; + margin-top: 12px; + cursor: pointer; +} + +input[type="range"]::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 20px; + height: 20px; + border-radius: 50%; + background: #fff; + border: 2px solid var(--primary); + cursor: pointer; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + transition: all 0.2s ease; +} + +input[type="range"]::-moz-range-thumb { + width: 18px; + height: 18px; + border-radius: 50%; + background: #fff; + border: 2px solid var(--primary); + cursor: pointer; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + transition: all 0.2s ease; +} + +input[type="range"]::-webkit-slider-thumb:hover, +input[type="range"]::-moz-range-thumb:hover { + transform: scale(1.1); + box-shadow: 0 3px 6px rgba(0, 0, 0, 0.15); +} + +input[type="range"]:focus::-webkit-slider-thumb { + box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.2); +} + +input[type="range"]:focus::-moz-range-thumb { + box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.2); +} + +.rating-slider-container { + margin-top: 10px; +} + +.rating-value { + display: inline-block; + font-size: 1.125em; + font-weight: 600; + color: var(--primary); + background: rgba(37, 99, 235, 0.08); + padding: 6px 12px; + border-radius: 8px; + margin-left: 12px; + transition: all 0.2s ease; +} + +.rating-value:hover { + transform: scale(1.05); + background: rgba(37, 99, 235, 0.12); +} + +.rating-scale { + display: flex; + justify-content: space-between; + margin-top: 8px; + font-size: 0.875em; + color: var(--text-secondary); + font-weight: 500; + padding: 0 2px; +} + +.rating-scale span { + opacity: 0.8; + transition: opacity 0.2s ease; +} + +.rating-scale span:hover { + opacity: 1; + color: var(--text-primary); +} + +button[type="submit"] { + background: var(--primary); + color: #fff; + border: none; + border-radius: 12px; + padding: 16px 0; + font-size: 1.125em; + font-weight: 600; + font-family: 'Inter', sans-serif; + cursor: pointer; + margin-top: 16px; + width: 100%; + position: relative; + overflow: hidden; + transition: all 0.3s ease; +} + +button[type="submit"]::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient( + to right, + rgba(255, 255, 255, 0) 0%, + rgba(255, 255, 255, 0.1) 50%, + rgba(255, 255, 255, 0) 100% + ); + transform: translateX(-100%); + transition: transform 0.6s ease; +} + +button[type="submit"]:hover { + background: var(--primary-dark); + transform: translateY(-1px); +} + +button[type="submit"]:hover::before { + transform: translateX(100%); +} + +button[type="submit"]:active { + transform: translateY(1px); +} + +button[type="submit"]:focus { + box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.4); + outline: none; +} + +button[type="submit"]:disabled { + background: var(--text-secondary); + opacity: 0.6; + cursor: not-allowed; + transform: none; +} + +button[type="submit"]:disabled::before { + display: none; +} + +.message { + margin-top: 24px; + padding: 16px; + background: rgba(37, 99, 235, 0.05); + color: var(--text-primary); + border-radius: 12px; + font-size: 1em; + text-align: center; + font-weight: 500; + border: 1px solid rgba(37, 99, 235, 0.1); + animation: slideIn 0.3s ease-out; +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.message.success { + background: rgba(5, 150, 105, 0.05); + color: var(--success); + border-color: rgba(5, 150, 105, 0.1); +} + +.message.error { + background: rgba(220, 38, 38, 0.05); + color: var(--error); + border-color: rgba(220, 38, 38, 0.1); +} + +@media (max-width: 600px) { + .App { + padding: 0px; + width: 100%; + } + .match-rating { + padding: 20px 16px; + margin: 16px auto; + border-radius: 20px; + width: 98%; + } + .form-group { + margin-bottom: 16px; + } + .rating-value { + display: block; + margin: 8px 0 0 0; + text-align: center; + width: 100%; + } + select { + padding: 14px; + font-size: 16px; + } + button[type="submit"] { + font-size: 16px; + padding: 16px 0; + width: 100%; + margin-top: 20px; + } + .message { + font-size: 14px; + padding: 12px; + margin-top: 16px; + width: 100%; + } +} + +@media (max-width: 400px) { + .match-rating { + padding: 20px 14px; + margin: 12px auto; + border-radius: 16px; + } + + .match-rating h2 { + font-size: 1.3em; + margin-bottom: 16px; + } +} + +@media (max-width: 320px) { + .match-rating { + padding: 16px 12px; + margin: 8px auto; + border-radius: 14px; + } + + .match-rating h2 { + font-size: 1.2em; + margin-bottom: 14px; + } +} + +/* Delete duplicate styles as they are now consolidated above */ + +.form-group { + margin-bottom: 18px; + text-align: left; +} + +label { + display: block; + margin-bottom: 8px; + font-size: 1em; + color: #333; +} + +select, input[type="range"] { + border-radius: 8px; + border: 1px solid #e0e0e0; + font-size: 1em; + background: #fafbfc; +} + +select { + width: 100%; + padding: 10px; + margin-bottom: 2px; +} + +input[type="range"] { + width: 100%; + height: 8px; + border-radius: 4px; + background: #e6eaf0; + outline: none; + opacity: 0.85; + transition: opacity 0.2s; +} + +.rating-slider-container { + margin-top: 6px; +} + +.rating-value { + font-size: 1.1em; + font-weight: 600; + color: #2196f3; + background: #e3f2fd; + padding: 3px 10px; + border-radius: 6px; + margin-left: 10px; +} + +.rating-scale { + display: flex; + justify-content: space-between; + margin-top: 4px; + font-size: 0.95em; + color: #888; +} + +button[type="submit"] { + background: linear-gradient(90deg, #2196f3 60%, #21cbf3 100%); + color: #fff; + border: none; + border-radius: 8px; + padding: 12px 0; + font-size: 1.1em; + font-weight: 600; + cursor: pointer; + margin-top: 8px; + box-shadow: 0 1px 4px 0 rgba(33,150,243,0.08); + transition: background 0.2s; +} + +button[type="submit"]:hover { + background: linear-gradient(90deg, #1976d2 60%, #21cbf3 100%); +} + +button[type="submit"]:disabled { + background: #b0bec5; + color: #f5f5f5; + cursor: not-allowed; +} + +.message { + margin-top: 18px; + padding: 10px; + background: #f1f8e9; + color: #33691e; + border-radius: 6px; + font-size: 1em; + text-align: center; +} + +/* Responsive styles */ +@media (max-width: 600px) { + .match-rating { + padding: 24px 16px; + margin: 16px auto; + border-radius: 20px; + width: 18rem; + } + + .match-rating h2 { + font-size: 1.4em; + margin-bottom: 20px; + } } .App-logo { @@ -17,15 +492,19 @@ } .App-header { - background-color: #282c34; - min-height: 100vh; + background: linear-gradient(120deg, #232946 60%, #3b2f63 100%); + min-height: 40vh; display: flex; + width: 100%; flex-direction: column; align-items: center; justify-content: center; font-size: calc(10px + 2vmin); - color: white; + color: #fff; + padding: 0px 20px; margin-bottom: 30px; + border-radius: 0 0 4rem 4rem; + box-shadow: 0 2px 16px 0 rgba(44,44,80,0.13); } .App-link { @@ -42,57 +521,252 @@ } .tabs { - display: flex; - justify-content: center; + display: inline-flex; + background: rgba(255, 255, 255, 0.1); + padding: 4px; + border-radius: 12px; margin-top: 20px; + box-shadow: + 0 4px 6px rgba(0, 0, 0, 0.1), + inset 0 1px 1px rgba(255, 255, 255, 0.1); + backdrop-filter: blur(8px); } .tabs button { - background-color: #f0f0f0; - border: 1px solid #ccc; - padding: 10px 20px; + background: transparent; + border: none; + padding: 12px 24px; cursor: pointer; - font-size: 16px; - transition: background-color 0.3s; + font-size: 15px; + font-weight: 500; + color: rgba(255, 255, 255, 0.8); + border-radius: 8px; + transition: all 0.3s ease; + position: relative; + letter-spacing: 0.3px; + min-width: 120px; +} + +.tabs button:hover:not(.active) { + color: white; + background: rgba(255, 255, 255, 0.1); } .tabs button.active { - background-color: #61dafb; + background: #38bdf8; color: white; + font-weight: 600; + box-shadow: + 0 2px 4px rgba(0, 0, 0, 0.1), + 0 1px 2px rgba(0, 0, 0, 0.06); +} + +.tabs button:first-child { + margin-right: 2px; +} + +@media (max-width: 600px) { + .tabs button { + padding: 10px 16px; + font-size: 14px; + min-width: 100px; + } + .tabs { + border-radius: 10px; + padding: 3px; + } } table { width: 100%; - border-collapse: collapse; - margin-top: 20px; + border-collapse: separate; + border-spacing: 0; + margin-top: 24px; + background: var(--card-bg); + border-radius: 16px; + overflow: hidden; + box-shadow: + 0 4px 6px -1px rgba(0, 0, 0, 0.1), + 0 2px 4px -1px rgba(0, 0, 0, 0.06); } -table th, table td { - border: 1px solid #ddd; - padding: 12px; +table th { + background: rgba(37, 99, 235, 0.03); + color: var(--text-primary); + font-weight: 600; + font-size: 0.95em; + text-transform: uppercase; + letter-spacing: 0.025em; + padding: 16px; text-align: left; + border-bottom: 2px solid var(--border); } -table th { - background-color: #f2f2f2; +table td { + padding: 16px; + color: var(--text-secondary); + font-size: 0.95em; + border-bottom: 1px solid var(--border); + transition: background-color 0.2s ease; +} + +table tbody tr:hover td { + background-color: rgba(37, 99, 235, 0.02); +} + +table tbody tr:last-child td { + border-bottom: none; +} + +table th:first-child { + border-top-left-radius: 16px; +} + +table th:last-child { + border-top-right-radius: 16px; +} + +table tbody tr:last-child td:first-child { + border-bottom-left-radius: 16px; +} + +table tbody tr:last-child td:last-child { + border-bottom-right-radius: 16px; +} + +@media (max-width: 600px) { + table { + border-radius: 12px; + margin: 16px -8px; + width: calc(100% + 16px); + } + table th, table td { + padding: 12px 8px; + font-size: 14px; + } +} + +@media (max-width: 400px) { + table { + margin: 12px -4px; + width: calc(100% + 8px); + } + table th, table td { + padding: 10px 6px; + font-size: 13px; + } +} + +@media (max-width: 320px) { + table th, table td { + padding: 8px 4px; + font-size: 12px; + } + table th { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } +} + +.table-container { + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + margin: 0 -8px; + padding: 0 8px; + scrollbar-width: thin; +} + +.table-container::-webkit-scrollbar { + height: 6px; +} + +.table-container::-webkit-scrollbar-track { + background: var(--background); + border-radius: 3px; +} + +.table-container::-webkit-scrollbar-thumb { + background: var(--border); + border-radius: 3px; +} + +.table-container::-webkit-scrollbar-thumb:hover { + background: var(--text-secondary); } .form-group { margin-bottom: 20px; - text-align: left; + max-width: 100vw; } label { display: block; margin-bottom: 8px; + max-width: 98vw; } -select, input[type="range"] { +select { width: 100%; padding: 8px; box-sizing: border-box; } +input[type="range"] { + width: 100%; + height: 8px; + border-radius: 4px; + background: #ddd; + outline: none; + opacity: 0.7; + transition: opacity 0.2s; +} + +input[type="range"]:hover { + opacity: 1; +} + +input[type="range"]::-webkit-slider-thumb { + appearance: none; + width: 20px; + height: 20px; + border-radius: 50%; + background: #61dafb; + cursor: pointer; +} + +input[type="range"]::-moz-range-thumb { + width: 20px; + height: 20px; + border-radius: 50%; + background: #61dafb; + cursor: pointer; + border: none; +} + +.rating-value { + font-size: 1.2em; + font-weight: bold; + color: #61dafb; + background-color: #f0f8ff; + padding: 4px 8px; + border-radius: 4px; + margin-left: 10px; +} + +.rating-slider-container { + position: relative; +} + +.rating-scale { + display: flex; + justify-content: space-between; + margin-top: 5px; + font-size: 0.9em; + color: #666; +} + button[type="submit"] { background-color: #61dafb; color: white; @@ -117,4 +791,4 @@ button[type="submit"]:disabled { padding: 10px; background-color: #f8f9fa; border-radius: 4px; -} +} \ No newline at end of file diff --git a/code-challenge/src/api/ratingApi.js b/code-challenge/src/api/ratingApi.js index 651950947..aae28dd9a 100644 --- a/code-challenge/src/api/ratingApi.js +++ b/code-challenge/src/api/ratingApi.js @@ -4,14 +4,9 @@ import { updatePlayers } from './playerApi'; export const storeRating = async (playerId, rating) => { const ratingsStr = localStorage.getItem('ratings') || '{}'; const ratings = JSON.parse(ratingsStr); - - if (!ratings[playerId]) { - ratings[playerId] = []; - } - + if (!ratings[playerId]) ratings[playerId] = []; ratings[playerId].push(rating); localStorage.setItem('ratings', JSON.stringify(ratings)); - return ratings[playerId]; }; @@ -20,11 +15,7 @@ export const calculateAverageRating = async (playerId) => { const ratingsStr = localStorage.getItem('ratings') || '{}'; const ratings = JSON.parse(ratingsStr); const playerRatings = ratings[playerId] || []; - - await new Promise(resolve => setTimeout(resolve, 10000)); - if (playerRatings.length === 0) return 0; - const sum = playerRatings.reduce((acc, rating) => acc + rating, 0); return sum / playerRatings.length; }; diff --git a/code-challenge/src/components/MatchRating.js b/code-challenge/src/components/MatchRating.js index aab3b90f7..3cf7eb5ca 100644 --- a/code-challenge/src/components/MatchRating.js +++ b/code-challenge/src/components/MatchRating.js @@ -32,14 +32,15 @@ const MatchRating = ({ players, setPlayers }) => { return (