Character Creator

Added the character creation page.
This commit is contained in:
Marces Zastrow
2025-01-10 12:05:05 +01:00
parent b56b73754c
commit 9c45795e80
6 changed files with 385 additions and 344 deletions
+346 -342
View File
@@ -2,17 +2,19 @@ import React, { useState, useContext } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { UserContext } from '../context/UserContext';
import axios from 'axios';
import {
Box,
TextField,
Button,
Typography,
Select,
MenuItem,
FormControl,
InputLabel,
Grid2
} from '@mui/material';
import { Box, TextField, Button, Typography, Select, MenuItem, FormControl, InputLabel, Grid2, Card, CardContent, CardMedia, Menu } from '@mui/material';
// Import the same icons as in games.jsx
import PaidIcon from '@mui/icons-material/Paid';
import CalendarTodayIcon from '@mui/icons-material/CalendarToday';
import PetsIcon from '@mui/icons-material/Pets';
import WcIcon from '@mui/icons-material/Wc';
import WorkIcon from '@mui/icons-material/Work';
import HeartIcon from '@mui/icons-material/Favorite';
import WaterDropIcon from '@mui/icons-material/WaterDrop';
import KeyboardDoubleArrowUpIcon from '@mui/icons-material/KeyboardDoubleArrowUp';
import defaultCharacterImage from '../assets/default-character.png';
const CreateCharacter = () => {
const navigate = useNavigate();
@@ -57,363 +59,365 @@ const CreateCharacter = () => {
e.preventDefault();
const formDataToSend = new FormData();
// Append all form data
// Add all form data
Object.keys(formData).forEach(key => {
formDataToSend.append(key, formData[key]);
formDataToSend.append(key, formData[key]);
});
// Append image if exists
// Add image if selected
if (selectedImage) {
formDataToSend.append('image', selectedImage);
formDataToSend.append('image', selectedImage);
}
// Add gameId and playerId
formDataToSend.append('gameId', gameId);
formDataToSend.append('playerId', userId);
try {
await axios.post('http://localhost:5000/games/character/create',
formDataToSend,
{
headers: {
'Content-Type': 'multipart/form-data'
}
const response = await axios.post(
'http://localhost:5000/games/character/create',
formDataToSend,
{
headers: {
'Content-Type': 'multipart/form-data'
}
}
);
if (response.status === 201) {
// Redirect to the game page after successful character creation
navigate(`/games/${gameId}`);
}
);
navigate(`/games/${gameId}`);
} catch (error) {
console.error('Error creating character:', error);
console.error('Error creating character:', error);
// You might want to show an error message to the user here
}
};
const inputStyles = {
'& .MuiOutlinedInput-root': {
'& fieldset': { borderColor: '#444' },
'&:hover fieldset': { borderColor: '#764ACB' },
'&.Mui-focused fieldset': { borderColor: '#764ACB' },
},
'& .MuiInputLabel-root': { color: '#fff' },
'& .MuiInputBase-input': { color: '#fff' }
};
return (
<Box sx={{
p: 3,
background: 'rgba(30, 30, 47, 0.9)',
borderRadius: '8px',
marginTop: '40px',
maxWidth: '800px',
margin: '40px auto'
}}>
<Typography variant="h4" sx={{ mb: 4, color: '#fff', textAlign: 'center' }}>
Create New Character
</Typography>
<Box sx={{ p: 3, background: 'rgba(30, 30, 47, 0.9)', borderRadius: '8px', marginTop: '40px' }}>
<form onSubmit={handleSubmit}>
<Grid2 container spacing={2}>
{/* Basic Info */}
<Grid2 item xs={12}>
<TextField
fullWidth
label="Character Name"
name="charName"
value={formData.charName}
onChange={handleChange}
required
sx={{
'& .MuiOutlinedInput-root': {
'& fieldset': {
borderColor: '#444',
},
'&:hover fieldset': {
borderColor: '#764ACB',
},
'&.Mui-focused fieldset': {
borderColor: '#764ACB',
},
},
'& .MuiInputLabel-root': {
color: '#fff',
},
'& .MuiInputBase-input': {
color: '#fff',
}
}}
/>
</Grid2>
<Grid2 container spacing={3}>
{/* Character Image and Details */}
<Grid2 item xs={12} md={4}>
<Box sx={{ border: '1px solid #444', borderRadius: '3px', p: 2, backgroundColor: '#2e2e3f' }}>
<Card sx={{ width: '400px', backgroundColor: '#1e1e2f', color: '#fff', height: '635px' }}>
{imagePreview ? (
<Box
component="label"
htmlFor="image-upload"
sx={{
cursor: 'pointer',
position: 'relative',
'&:hover::after': {
content: '"Change Image"',
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'rgba(0,0,0,0.5)',
color: '#fff',
fontSize: '1.2rem',
borderRadius: '3px'
}
}}
>
<input
accept="image/*"
type="file"
id="image-upload"
style={{ display: 'none' }}
onChange={handleImageChange}
/>
<CardMedia
component="img"
height="300"
image={imagePreview}
alt="Character Preview"
sx={{ borderRadius: '3px', objectFit: 'cover', margin: '0 auto' }}
/>
</Box>
) : (
<Box
sx={{
height: 300,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#2e2e3f',
borderRadius: '3px',
cursor: 'pointer'
}}
component="label"
htmlFor="image-upload"
>
<input
accept="image/*"
type="file"
id="image-upload"
style={{ display: 'none' }}
onChange={handleImageChange}
/>
<Button
variant="contained"
component="span"
sx={{
backgroundColor: '#764ACB',
'&:hover': { backgroundColor: '#9865f7' }
}}
>
Upload Character Image
</Button>
</Box>
)}
<CardContent sx={{
padding: '4px',
display: 'flex',
flexDirection: 'column',
alignItems: 'center'
}}>
<TextField
label="Character Name"
name="charName"
value={formData.charName}
onChange={handleChange}
required
sx={{
mb: 4,
width: '315px',
'& .MuiOutlinedInput-root': {
'& fieldset': { borderColor: '#444' },
'&:hover fieldset': { borderColor: '#764ACB' },
},
'& .MuiInputLabel-root': { color: '#fff' },
'& .MuiInputBase-input': { color: '#fff', textAlign: 'center' }
}}
/>
{/* Image Upload */}
<Grid2 item xs={12}>
<input
accept="image/*"
type="file"
id="image-upload"
style={{ display: 'none' }}
onChange={handleImageChange}
/>
<label htmlFor="image-upload">
<Button
variant="contained"
component="span"
sx={{
backgroundColor: '#764ACB',
'&:hover': { backgroundColor: '#9865f7' },
mb: 2
}}
>
Upload Character Image
</Button>
</label>
{imagePreview && (
<Box sx={{ mt: 2, mb: 2 }}>
<img
src={imagePreview}
alt="Preview"
style={{
maxWidth: '200px',
borderRadius: '4px',
border: '1px solid #444'
}}
/>
</Box>
)}
</Grid2>
<Grid2 container spacing={2} sx={{ maxWidth: '600px', justifyContent: 'center' }}>
<Grid2 item xs={5}>
<TextField
fullWidth
label="Age"
name="age"
type="number"
value={formData.age}
onChange={handleChange}
required
sx={{ ...inputStyles, width: '150px' }}
/>
</Grid2>
<Grid2 item xs={5}>
<TextField
fullWidth
label="Race"
name="race"
value={formData.race}
onChange={handleChange}
required
sx={{ ...inputStyles, width: '150px' }}
/>
</Grid2>
<Grid2 item xs={5}>
<FormControl fullWidth>
<InputLabel sx={{ color: '#fff' }}>Sex</InputLabel>
<Select
name="sex"
value={formData.sex}
onChange={handleChange}
required
sx={{
color: '#fff',
'& .MuiOutlinedInput-notchedOutline': { borderColor: '#444' },
'&:hover .MuiOutlinedInput-notchedOutline': { borderColor: '#764ACB' },
width: '150px'
}}
>
<MenuItem value="Male">Male</MenuItem>
<MenuItem value="Female">Female</MenuItem>
<MenuItem value="Other">Other</MenuItem>
</Select>
</FormControl>
</Grid2>
<Grid2 item xs={5}>
<TextField
fullWidth
label="Job/Class"
name="job"
value={formData.job}
onChange={handleChange}
required
sx={{ ...inputStyles, width: '150px' }}
/>
</Grid2>
</Grid2>
</CardContent>
</Card>
</Box>
</Grid2 >
{/* Character Details */}
<Grid2 container item spacing={2}>
<Grid2 item xs={12} md={6}>
<FormControl fullWidth sx={{ mb: 2 }}>
<InputLabel sx={{ color: '#fff' }}>Race</InputLabel>
<Select
name="race"
value={formData.race}
<Grid2 item xs={12} md={8}>
{/* Health/Mana Bars - Keep existing */}
<Box sx={{ display: 'flex', gap: 2, mb: 4, width: '885px' }}>
<Box sx={{ flex: 1, backgroundColor: '#2e2e3f', borderRadius: '8px', p: 2, border: '1px solid #444' }}>
<Typography variant="body1" sx={{ display: 'flex', justifyContent: 'space-between', color: '#fff' }}>
<HeartIcon sx={{ color: "red" }} />
<span>Max Health</span>
</Typography>
<TextField
fullWidth
name="maxHealth"
type="number"
value={formData.maxHealth}
onChange={handleChange}
required
sx={{
color: '#fff',
'& .MuiOutlinedInput-notchedOutline': {
borderColor: '#444',
'& .MuiOutlinedInput-root': {
'& fieldset': { borderColor: '#444' },
'&:hover fieldset': { borderColor: '#764ACB' },
},
'&:hover .MuiOutlinedInput-notchedOutline': {
borderColor: '#764ACB',
},
'&.Mui-focused .MuiOutlinedInput-notchedOutline': {
borderColor: '#764ACB',
},
'& .MuiSelect-icon': {
color: '#fff',
}
'& .MuiInputBase-input': { color: '#fff' }
}}
>
<MenuItem value="Human">Human</MenuItem>
<MenuItem value="Elf">Elf</MenuItem>
<MenuItem value="Dwarf">Dwarf</MenuItem>
<MenuItem value="Orc">Orc</MenuItem>
</Select>
</FormControl>
</Grid2>
<Grid2 item xs={12} md={6}>
<FormControl fullWidth>
<InputLabel sx={{ color: '#fff' }}>Sex</InputLabel>
<Select
name="sex"
value={formData.sex}
/>
</Box>
<Box sx={{ flex: 1, backgroundColor: '#2e2e3f', borderRadius: '8px', p: 2, border: '1px solid #444' }}>
<Typography variant="body1" sx={{ display: 'flex', justifyContent: 'space-between', color: '#fff' }}>
<WaterDropIcon sx={{ color: 'blue' }} />
<span>Max Mana</span>
</Typography>
<TextField
fullWidth
name="maxMana"
type="number"
value={formData.maxMana}
onChange={handleChange}
required
sx={{ color: '#fff', '& fieldset': { borderColor: '#444' } }}
>
<MenuItem value="Male">Male</MenuItem>
<MenuItem value="Female">Female</MenuItem>
<MenuItem value="Other">Other</MenuItem>
</Select>
</FormControl>
</Grid2>
<Grid2 item xs={12} md={6}>
<TextField
fullWidth
label="Age"
name="age"
type="number"
value={formData.age}
onChange={handleChange}
required
sx={{
'& .MuiOutlinedInput-root': {
'& fieldset': { borderColor: '#444' },
'&:hover fieldset': { borderColor: '#764ACB' },
},
'& .MuiInputLabel-root': { color: '#fff' },
'& .MuiInputBase-input': { color: '#fff' }
}}
/>
</Grid2>
<Grid2 item xs={12} md={6}>
<TextField
fullWidth
label="Job/Class"
name="job"
value={formData.job}
onChange={handleChange}
required
sx={{
'& .MuiOutlinedInput-root': {
'& fieldset': { borderColor: '#444' },
'&:hover fieldset': { borderColor: '#764ACB' },
},
'& .MuiInputLabel-root': { color: '#fff' },
'& .MuiInputBase-input': { color: '#fff' }
}}
/>
</Grid2>
{/* Stats */}
<Grid2 item xs={12} md={6}>
<TextField
fullWidth
label="Max Health"
name="maxHealth"
type="number"
value={formData.maxHealth}
onChange={handleChange}
required
sx={{
'& .MuiOutlinedInput-root': {
'& fieldset': { borderColor: '#444' },
'&:hover fieldset': { borderColor: '#764ACB' },
},
'& .MuiInputLabel-root': { color: '#fff' },
'& .MuiInputBase-input': { color: '#fff' }
}}
/>
</Grid2>
<Grid2 item xs={12} md={6}>
<TextField
fullWidth
label="Max Mana"
name="maxMana"
type="number"
value={formData.maxMana}
onChange={handleChange}
required
sx={{
'& .MuiOutlinedInput-root': {
'& fieldset': { borderColor: '#444' },
'&:hover fieldset': { borderColor: '#764ACB' },
},
'& .MuiInputLabel-root': { color: '#fff' },
'& .MuiInputBase-input': { color: '#fff' }
}}
/>
</Grid2>
<Grid2 item xs={12} md={6}>
<TextField
fullWidth
label="Strength"
name="strength"
type="number"
value={formData.strength}
onChange={handleChange}
required
sx={{
'& .MuiOutlinedInput-root': {
'& fieldset': { borderColor: '#444' },
'&:hover fieldset': { borderColor: '#764ACB' },
},
'& .MuiInputLabel-root': { color: '#fff' },
'& .MuiInputBase-input': { color: '#fff' }
}}
/>
</Grid2>
<Grid2 item xs={12} md={6}>
<TextField
fullWidth
label="Dexterity"
name="dexterity"
type="number"
value={formData.dexterity}
onChange={handleChange}
required
sx={{
'& .MuiOutlinedInput-root': {
'& fieldset': { borderColor: '#444' },
'&:hover fieldset': { borderColor: '#764ACB' },
},
'& .MuiInputLabel-root': { color: '#fff' },
'& .MuiInputBase-input': { color: '#fff' }
}}
/>
</Grid2>
<Grid2 item xs={12} md={6}>
<TextField
fullWidth
label="Agility"
name="agility"
type="number"
value={formData.agility}
onChange={handleChange}
required
sx={{
'& .MuiOutlinedInput-root': {
'& fieldset': { borderColor: '#444' },
'&:hover fieldset': { borderColor: '#764ACB' },
},
'& .MuiInputLabel-root': { color: '#fff' },
'& .MuiInputBase-input': { color: '#fff' }
}}
/>
</Grid2>
<Grid2 item xs={12} md={6}>
<TextField
fullWidth
label="Endurance"
name="endurance"
type="number"
value={formData.endurance}
onChange={handleChange}
required
sx={{
'& .MuiOutlinedInput-root': {
'& fieldset': { borderColor: '#444' },
'&:hover fieldset': { borderColor: '#764ACB' },
},
'& .MuiInputLabel-root': { color: '#fff' },
'& .MuiInputBase-input': { color: '#fff' }
}}
/>
</Grid2>
sx={{
'& .MuiOutlinedInput-root': {
'& fieldset': { borderColor: '#444' },
'&:hover fieldset': { borderColor: '#764ACB' },
},
'& .MuiInputBase-input': { color: '#fff' }
}}
/>
</Box>
</Box>
{/* Description */}
<Grid2 item xs={12}>
<TextField
fullWidth
label="Description"
name="description"
multiline
rows={4}
value={formData.description}
onChange={handleChange}
sx={{
'& .MuiOutlinedInput-root': {
'& fieldset': { borderColor: '#444' },
'&:hover fieldset': { borderColor: '#764ACB' },
},
'& .MuiInputLabel-root': { color: '#fff' },
'& .MuiInputBase-input': { color: '#fff' }
}}
/>
</Grid2>
</Grid2>
</Grid2>
<Box sx={{ mb: 4 }}>
<Typography variant="h5" sx={{ color: '#fff', mb: 2 }}>Description</Typography>
<Box sx={{ backgroundColor: '#2e2e3f', p: 2, borderRadius: '8px', border: '1px solid #444' }}>
<TextField
fullWidth
multiline
rows={4}
name="description"
value={formData.description}
onChange={handleChange}
sx={{
'& .MuiOutlinedInput-root': {
'& fieldset': { borderColor: '#444' },
'&:hover fieldset': { borderColor: '#764ACB' },
},
'& .MuiInputBase-input': { color: '#fff' }
}}
/>
</Box>
</Box>
<Button
type="submit"
variant="contained"
fullWidth
sx={{
backgroundColor: '#764ACB',
'&:hover': { backgroundColor: '#9865f7' },
mt: 3
}}
>
Create Character
</Button>
</form>
</Box>
{/* Stats Grid */}
<Box sx={{ mb: 4 }}>
<Typography variant="h5" sx={{ color: '#fff', mb: 2 }}>Character Stats</Typography>
<Box sx={{
backgroundColor: '#2e2e3f',
p: 2,
borderRadius: '8px',
border: '1px solid #444',
maxWidth: '800px',
margin: '0 auto'
}}>
<Grid2 container spacing={3} justifyContent="center">
<Grid2 item xs={10} md={2}>
<TextField
fullWidth
label="Strength"
name="strength"
type="number"
value={formData.strength}
onChange={handleChange}
sx={{ ...inputStyles }}
/>
</Grid2>
<Grid2 item xs={10} md={2}>
<TextField
fullWidth
label="Dexterity"
name="dexterity"
type="number"
value={formData.dexterity}
onChange={handleChange}
sx={{ ...inputStyles }}
/>
</Grid2>
<Grid2 item xs={10} md={2}>
<TextField
fullWidth
label="Agility"
name="agility"
type="number"
value={formData.agility}
onChange={handleChange}
sx={{ ...inputStyles }}
/>
</Grid2>
<Grid2 item xs={10} md={2}>
<TextField
fullWidth
label="Endurance"
name="endurance"
type="number"
value={formData.endurance}
onChange={handleChange}
sx={{ ...inputStyles }}
/>
</Grid2>
</Grid2>
</Box>
</Box>
{/* Submit Button */}
<Button
type="submit"
variant="contained"
fullWidth
sx={{
backgroundColor: '#764ACB',
'&:hover': { backgroundColor: '#9865f7' },
mt: 3
}}
>
Create Character
</Button>
</Grid2>
</Grid2 >
</form >
</Box >
);
};
export default CreateCharacter;
export default CreateCharacter;