Skip to content

Commit

Permalink
Merge pull request #2 from Jose26398/interface-improvements
Browse files Browse the repository at this point in the history
Interface improvements
  • Loading branch information
Jose26398 authored Jan 11, 2025
2 parents 62f272f + 3bf38e9 commit 07a6325
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 98 deletions.
2 changes: 1 addition & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function App() {

{/* Tab Content */}
{activeTab === 'matches' && (
<div className="grid gap-6">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{matches.length > 0 ? (
matches.map(match => (
<MatchCard key={match.id} match={match} onEdit={editMatch} onDelete={deleteMatch} />
Expand Down
64 changes: 37 additions & 27 deletions src/components/MatchCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,60 +29,70 @@ export function MatchCard({ match, onEdit, onDelete }: MatchCardProps) {
};

return (
<div className="bg-white rounded-lg shadow-md p-4">
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-2 text-gray-600">
<Calendar className="w-4 h-4" />
<span>{format(new Date(match.date), 'PPP', { locale: es })}</span>
<div className="bg-white rounded-lg shadow-md p-5 hover:shadow-lg transition-shadow">
{/* Header */}
<div className="flex items-center justify-between mb-5">
<div className="flex items-center gap-3 text-gray-500">
<Calendar className="w-5 h-5" />
<span className="text-sm font-medium">{format(new Date(match.date), 'PPP', { locale: es })}</span>
</div>
<div className="flex items-center gap-2">
<div className="flex items-center gap-3">
<button
onClick={() => setIsEditing(true)}
className="p-2 text-emerald-600 hover:bg-emerald-50 rounded-full transition-colors"
className='rounded-full text-emerald-600 hover:text-emerald-200 transition-colors'
title="Editar partido"
aria-label="Editar partido"
>
<Edit className="w-5 h-5" />
</button>
<button
onClick={handleDelete}
className="text-red-500 hover:text-red-700 transition-colors"
className='rounded-full text-red-600 hover:text-red-200 transition-colors'
title="Eliminar partido"
aria-label="Eliminar partido"
>
<Trash2 className="w-5 h-5" />
</button>
</div>
</div>

<div className="grid grid-cols-3 gap-4 align-top">

{/* Match Details */}
<div className="grid grid-cols-3 gap-6 align-top">
{/* Team A */}
<div className="text-center">
<div className="font-semibold mb-2">Equipo A</div>
<div className="text-2xl font-bold text-emerald-600">{match.teamA.score}</div>
<div className="mt-2 text-sm text-gray-600">
<div className="text-gray-700 font-semibold mb-2">Equipo A</div>
<div className="text-3xl font-bold text-emerald-600">{match.teamA.score}</div>
<div className="mt-2 text-sm text-gray-500">
{match.teamA.players.map(p => p.name).join(', ')}
</div>
</div>

<div className="text-center text-gray-400">vs</div>


<div className="text-center text-gray-400 text-xl font-bold">vs</div>

{/* Team B */}
<div className="text-center">
<div className="font-semibold mb-2">Equipo B</div>
<div className="text-2xl font-bold text-emerald-600">{match.teamB.score}</div>
<div className="mt-2 text-sm text-gray-600">
<div className="text-gray-700 font-semibold mb-2">Equipo B</div>
<div className="text-3xl font-bold text-emerald-600">{match.teamB.score}</div>
<div className="mt-2 text-sm text-gray-500">
{match.teamB.players.map(p => p.name).join(', ')}
</div>
</div>
</div>


{/* Goals */}
{match.goals.length > 0 && (
<div className="mt-4 pt-4 border-t">
<div className="flex items-center gap-2 mb-2">
<Trophy className="w-4 h-4 text-yellow-500" />
<span className="font-semibold">Goles</span>
<div className="mt-6 pt-4 border-t border-gray-200">
<div className="flex items-center gap-3 mb-3">
<Trophy className="w-5 h-5 text-yellow-500" />
<span className="text-lg font-semibold text-gray-700">Goles</span>
</div>
<div className="text-sm text-gray-600">
<div className="text-sm text-gray-600 space-y-2">
{match.goals.map((goal, index) => (
<div key={index} className="mb-1">
<div key={index}>
{`${match.teamA.players.concat(match.teamB.players).find(p => p.id === goal.playerId)?.name} (${goal.minute}')`}
{goal.assistById && ` - Asistencia: ${match.teamA.players.concat(match.teamB.players).find(p => p.id === goal.assistById)?.name}`}
{goal.assistById && (
<span className="text-gray-500"> - Asistencia: {match.teamA.players.concat(match.teamB.players).find(p => p.id === goal.assistById)?.name}</span>
)}
</div>
))}
</div>
Expand Down
154 changes: 84 additions & 70 deletions src/components/PlayerCard.tsx
Original file line number Diff line number Diff line change
@@ -1,167 +1,181 @@
import { User, Trash2, Edit } from 'lucide-react';
import { useState } from 'react';
import { Player } from '../types';
import { calculateWinRate, calculateScore } from '../utils/playerStats';
import { User, Trash2, Edit } from 'lucide-react'
import { useState } from 'react'
import { Player } from '../types'
import { calculateWinRate, calculateScore } from '../utils/playerStats'

interface PlayerCardProps {
player: Player;
onDelete?: (id: string) => void;
onEdit?: (id: string, updatedData: Partial<Omit<Player, 'id'>>) => void;
player: Player
onDelete?: (id: string) => void
onEdit?: (id: string, updatedData: Partial<Omit<Player, 'id'>>) => void
}

export function PlayerCard({ player, onDelete, onEdit }: PlayerCardProps) {
const [isEditing, setIsEditing] = useState(false);
export function PlayerCard ({ player, onDelete, onEdit }: PlayerCardProps) {
const [isEditing, setIsEditing] = useState(false)
const [editedData, setEditedData] = useState<Partial<Omit<Player, 'id'>>>({
name: player.name,
matches: player.matches,
goals: player.goals,
assists: player.assists,
});
assists: player.assists
})

const winRate = calculateWinRate(player);
const score = calculateScore(player);
const winRate = calculateWinRate(player)
const score = calculateScore(player)

const handleEdit = () => {
setIsEditing(true);
};
setIsEditing(true)
}

const handleSave = () => {
if (onEdit) {
onEdit(player.id, editedData);
onEdit(player.id, editedData)
}
setIsEditing(false);
};
setIsEditing(false)
}

const handleCancel = () => {
setEditedData({
name: player.name,
matches: player.matches,
goals: player.goals,
assists: player.assists,
});
setIsEditing(false);
};
assists: player.assists
})
setIsEditing(false)
}

return (
<div className="bg-white rounded-lg shadow-md p-4 hover:shadow-lg transition-shadow">
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-3">
<User className="w-8 h-8 text-emerald-600" />
<h3 className="text-lg font-semibold">{player.name}</h3>
<div className='bg-white rounded-lg shadow-md p-5 hover:shadow-xl transition-shadow'>
{/* Header */}
<div className='flex items-center justify-between mb-4'>
<div className='flex items-center gap-4'>
<User className='w-10 h-10 text-emerald-600' />
<h3 className='text-xl font-bold text-gray-800'>{player.name}</h3>
</div>
<div className="flex items-center gap-4">
<div className='flex items-center gap-3'>
{onEdit && (
<button
onClick={handleEdit}
className="text-emerald-500 hover:text-emerald-700 transition-colors"
title="Editar jugador"
className='rounded-full text-emerald-600 hover:text-emerald-200 transition-colors'
title='Editar jugador'
aria-label='Editar jugador'
>
<Edit className="w-5 h-5" />
<Edit className='w-5 h-5' />
</button>
)}
{onDelete && (
<button
onClick={() => onDelete(player.id)}
className="text-red-500 hover:text-red-700 transition-colors"
title="Eliminar jugador"
className='rounded-full text-red-600 hover:text-red-200 transition-colors'
title='Eliminar jugador'
aria-label='Eliminar jugador'
>
<Trash2 className="w-5 h-5" />
<Trash2 className='w-5 h-5' />
</button>
)}
</div>
</div>
<div className="grid grid-cols-2 gap-2 text-sm">

{/* Stats Grid */}
<div className='grid grid-cols-2 gap-4 text-sm'>
<div>
<p className="text-gray-600">Partidos jugados</p>
<p className="font-medium">{player.matches}</p>
<p className='text-gray-500'>Partidos V/E/D</p>
<p className='text-lg font-medium text-gray-800'>
{player.wins}/{player.matches - player.wins - player.losses}/
{player.losses}
</p>
</div>
<div>
<p className="text-gray-600">Tasa de victorias</p>
<p className="font-medium">{winRate.toFixed(1)}%</p>
<p className='text-gray-500'>Tasa de victorias</p>
<p className='text-lg font-medium text-gray-800'>
{winRate.toFixed(1)}%
</p>
</div>
<div>
<p className="text-gray-600">Goles</p>
<p className="font-medium">{player.goals}</p>
<p className='text-gray-500'>Goles</p>
<p className='text-lg font-medium text-gray-800'>{player.goals}</p>
</div>
<div>
<p className="text-gray-600">Asistencias</p>
<p className="font-medium">{player.assists}</p>
<p className='text-gray-500'>Asistencias</p>
<p className='text-lg font-medium text-gray-800'>{player.assists}</p>
</div>
</div>
<div className="mt-3 pt-3 border-t">
<p className="text-gray-600 text-sm">Puntuación del jugador</p>
<p className="font-semibold text-emerald-600">{score.toFixed(1)}</p>

{/* Player Score */}
<div className='mt-5 pt-4 border-t border-gray-200'>
<p className='text-gray-500 text-sm'>Puntuación del jugador</p>
<p className='text-2xl font-bold text-emerald-600'>
{score.toFixed(1)}
</p>
</div>

{/* Modal for editing */}
{isEditing && (
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50">
<div className="bg-white p-6 rounded-lg shadow-lg w-96">
<h2 className="text-xl font-semibold mb-4">Edit Player</h2>
<form className="space-y-3">
<div className='fixed inset-0 flex items-center justify-center bg-black bg-opacity-50'>
<div className='bg-white p-6 rounded-lg shadow-lg w-96'>
<h2 className='text-xl font-semibold mb-4'>Edit Player</h2>
<form className='space-y-3'>
<div>
<label className="block text-sm font-medium text-gray-600">
<label className='block text-sm font-medium text-gray-600'>
Nombre
</label>
<input
type="text"
className="w-full border border-gray-300 rounded px-3 py-2"
type='text'
className='w-full border border-gray-300 rounded px-3 py-2'
value={editedData.name}
onChange={(e) =>
onChange={e =>
setEditedData({ ...editedData, name: e.target.value })
}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-600">
<label className='block text-sm font-medium text-gray-600'>
Partidos
</label>
<input
type="number"
className="w-full border border-gray-300 rounded px-3 py-2"
type='number'
className='w-full border border-gray-300 rounded px-3 py-2'
value={editedData.matches}
onChange={(e) =>
onChange={e =>
setEditedData({ ...editedData, matches: +e.target.value })
}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-600">
<label className='block text-sm font-medium text-gray-600'>
Goles
</label>
<input
type="number"
className="w-full border border-gray-300 rounded px-3 py-2"
type='number'
className='w-full border border-gray-300 rounded px-3 py-2'
value={editedData.goals}
onChange={(e) =>
onChange={e =>
setEditedData({ ...editedData, goals: +e.target.value })
}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-600">
<label className='block text-sm font-medium text-gray-600'>
Asistencias
</label>
<input
type="number"
className="w-full border border-gray-300 rounded px-3 py-2"
type='number'
className='w-full border border-gray-300 rounded px-3 py-2'
value={editedData.assists}
onChange={(e) =>
onChange={e =>
setEditedData({ ...editedData, assists: +e.target.value })
}
/>
</div>
</form>
<div className="flex justify-end gap-3 mt-4">
<div className='flex justify-end gap-3 mt-4'>
<button
onClick={handleCancel}
className="px-4 py-2 bg-gray-300 text-gray-700 rounded hover:bg-gray-400"
className='px-4 py-2 bg-gray-300 text-gray-700 rounded hover:bg-gray-400'
>
Cancelar
</button>
<button
onClick={handleSave}
className="px-4 py-2 bg-emerald-600 text-white rounded hover:bg-emerald-700"
className='px-4 py-2 bg-emerald-600 text-white rounded hover:bg-emerald-700'
>
Guardar
</button>
Expand All @@ -170,5 +184,5 @@ export function PlayerCard({ player, onDelete, onEdit }: PlayerCardProps) {
</div>
)}
</div>
);
)
}

0 comments on commit 07a6325

Please sign in to comment.