- Deleted redundant components (`AddActionButton`, `AlertBox`, `AlertStack`, `BackButton`, `CancelButton`, and `CollapsableArea`) and related files. - Removed unused models (`Book`, `BookSerie`, `BookTables`, `Character`, and `Chapter`) to reduce codebase clutter. - Updated project structure and references to reflect these removals.
318 lines
15 KiB
TypeScript
318 lines
15 KiB
TypeScript
'use client';
|
|
import {useState} from 'react';
|
|
import {ArrowLeft, Plus, Trash2} from 'lucide-react';
|
|
import Button from '@/components/ui/Button';
|
|
|
|
interface RelatedItem {
|
|
name: string;
|
|
type: string;
|
|
description: string;
|
|
history: string;
|
|
}
|
|
|
|
interface Item {
|
|
id: number | null;
|
|
name: string;
|
|
description: string;
|
|
history: string;
|
|
location: string;
|
|
ownedBy: string;
|
|
functionality: string;
|
|
image: string;
|
|
relatedItems: RelatedItem[];
|
|
}
|
|
|
|
const initialItemState: Item = {
|
|
id: null,
|
|
name: '',
|
|
description: '',
|
|
history: '',
|
|
location: '',
|
|
ownedBy: '',
|
|
functionality: '',
|
|
image: '',
|
|
relatedItems: [],
|
|
};
|
|
|
|
export default function Items() {
|
|
const [items, setItems] = useState<Item[]>([
|
|
{
|
|
id: 1,
|
|
name: 'Sword of Destiny',
|
|
description: 'A powerful sword',
|
|
history: 'Forged in the ancient times...',
|
|
location: 'Castle',
|
|
ownedBy: 'John Doe',
|
|
functionality: 'Cuts through anything',
|
|
image: 'https://via.placeholder.com/150',
|
|
relatedItems: []
|
|
},
|
|
{
|
|
id: 2,
|
|
name: 'Shield of Valor',
|
|
description: 'An unbreakable shield',
|
|
history: 'Used by the legendary hero...',
|
|
location: 'Fortress',
|
|
ownedBy: 'Jane Doe',
|
|
functionality: 'Deflects any attack',
|
|
image: 'https://via.placeholder.com/150',
|
|
relatedItems: []
|
|
}
|
|
]);
|
|
|
|
const [selectedItem, setSelectedItem] = useState<Item | null>(null);
|
|
const [searchQuery, setSearchQuery] = useState<string>('');
|
|
const [newItem, setNewItem] = useState<Item>(initialItemState);
|
|
const [newRelatedItem, setNewRelatedItem] = useState<RelatedItem>({
|
|
name: '',
|
|
type: '',
|
|
description: '',
|
|
history: ''
|
|
});
|
|
|
|
const filteredItems = items.filter(
|
|
(item) =>
|
|
item.name.toLowerCase().includes(searchQuery.toLowerCase())
|
|
);
|
|
|
|
const handleItemClick = (item: Item) => {
|
|
setSelectedItem(item);
|
|
};
|
|
|
|
const handleAddItem = () => {
|
|
setSelectedItem(newItem);
|
|
};
|
|
|
|
const handleSaveItem = () => {
|
|
if (selectedItem) {
|
|
if (selectedItem.id === null) {
|
|
setItems([...items, {...selectedItem, id: items.length + 1}]);
|
|
} else {
|
|
setItems(items.map((item) => (item.id === selectedItem.id ? selectedItem : item)));
|
|
}
|
|
setSelectedItem(null);
|
|
setNewItem(initialItemState);
|
|
}
|
|
};
|
|
|
|
const handleItemChange = (key: keyof Item, value: string) => {
|
|
if (selectedItem) {
|
|
setSelectedItem({...selectedItem, [key]: value});
|
|
}
|
|
};
|
|
|
|
const handleElementChange = (section: keyof Item, index: number, key: keyof RelatedItem, value: string) => {
|
|
if (selectedItem) {
|
|
const updatedSection = [...(selectedItem[section] as RelatedItem[])];
|
|
updatedSection[index][key] = value;
|
|
setSelectedItem({...selectedItem, [section]: updatedSection});
|
|
}
|
|
};
|
|
|
|
const handleAddElement = (section: keyof Item, value: RelatedItem) => {
|
|
if (selectedItem) {
|
|
const updatedSection = [...(selectedItem[section] as RelatedItem[]), value];
|
|
setSelectedItem({...selectedItem, [section]: updatedSection});
|
|
}
|
|
};
|
|
|
|
const handleRemoveElement = (section: keyof Item, index: number) => {
|
|
if (selectedItem) {
|
|
const updatedSection = (selectedItem[section] as RelatedItem[]).filter((_, i) => i !== index);
|
|
setSelectedItem({...selectedItem, [section]: updatedSection});
|
|
}
|
|
};
|
|
|
|
return (
|
|
<main className="flex-grow p-8 overflow-y-auto">
|
|
{selectedItem ? (
|
|
<div>
|
|
<div className="flex justify-between sticky top-0 z-10 bg-darkest-background py-4">
|
|
<Button variant="secondary" icon={ArrowLeft} onClick={() => setSelectedItem(null)}>
|
|
Back
|
|
</Button>
|
|
<h2 className="text-3xl font-['ADLaM_Display'] text-center text-text-primary">{selectedItem.name}</h2>
|
|
<Button variant="primary" onClick={handleSaveItem}>
|
|
Save Item
|
|
</Button>
|
|
</div>
|
|
<div className="bg-secondary rounded-lg p-8 shadow-lg space-y-4">
|
|
<div>
|
|
<label className="block text-text-primary mb-2" htmlFor="name">Name</label>
|
|
<input
|
|
type="text"
|
|
id="name"
|
|
value={selectedItem.name}
|
|
onChange={(e) => handleItemChange('name', e.target.value)}
|
|
className="input-base"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-text-primary mb-2" htmlFor="description">Description</label>
|
|
<textarea
|
|
id="description"
|
|
rows={4}
|
|
value={selectedItem.description}
|
|
onChange={(e) => handleItemChange('description', e.target.value)}
|
|
className="input-base"
|
|
></textarea>
|
|
</div>
|
|
<div>
|
|
<label className="block text-text-primary mb-2" htmlFor="history">History</label>
|
|
<textarea
|
|
id="history"
|
|
rows={4}
|
|
value={selectedItem.history}
|
|
onChange={(e) => handleItemChange('history', e.target.value)}
|
|
className="input-base"
|
|
></textarea>
|
|
</div>
|
|
<div>
|
|
<label className="block text-text-primary mb-2" htmlFor="location">Location</label>
|
|
<select
|
|
id="location"
|
|
value={selectedItem.location}
|
|
onChange={(e) => handleItemChange('location', e.target.value)}
|
|
className="input-base"
|
|
>
|
|
<option value="">Select Location</option>
|
|
<option value="Castle">Castle</option>
|
|
<option value="Fortress">Fortress</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label className="block text-text-primary mb-2" htmlFor="ownedBy">Owned By</label>
|
|
<select
|
|
id="ownedBy"
|
|
value={selectedItem.ownedBy}
|
|
onChange={(e) => handleItemChange('ownedBy', e.target.value)}
|
|
className="input-base"
|
|
>
|
|
<option value="">Select Owner</option>
|
|
{items.map((item) => (
|
|
<option key={item.id} value={item.name}>{item.name}</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label className="block text-text-primary mb-2" htmlFor="functionality">Functionality</label>
|
|
<textarea
|
|
id="functionality"
|
|
rows={4}
|
|
value={selectedItem.functionality}
|
|
onChange={(e) => handleItemChange('functionality', e.target.value)}
|
|
className="input-base"
|
|
></textarea>
|
|
</div>
|
|
<div>
|
|
<label className="block text-text-primary mb-2" htmlFor="image">Image URL</label>
|
|
<input
|
|
type="text"
|
|
id="image"
|
|
value={selectedItem.image}
|
|
onChange={(e) => handleItemChange('image', e.target.value)}
|
|
className="input-base"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="bg-secondary rounded-lg p-8 shadow-lg space-y-4 mt-4">
|
|
<h3 className="text-2xl font-['ADLaM_Display'] text-text-primary">Related Items</h3>
|
|
<div className="space-y-2">
|
|
{selectedItem.relatedItems.map((relatedItem, index) => (
|
|
<details key={index}
|
|
className="bg-secondary/30 rounded-xl mb-4 p-4 shadow-sm hover:shadow-md transition-all duration-200">
|
|
<summary className="text-lg text-text-primary cursor-pointer">{relatedItem.name}</summary>
|
|
<div className="mt-2">
|
|
<label className="block text-text-primary mb-2"
|
|
htmlFor={`related-item-description-${relatedItem.name}`}>Description</label>
|
|
<textarea
|
|
id={`related-item-description-${relatedItem.name}`}
|
|
rows={3}
|
|
value={relatedItem.description}
|
|
onChange={(e) => handleElementChange('relatedItems', index, 'description', e.target.value)}
|
|
className="input-base"
|
|
></textarea>
|
|
<label className="block text-text-primary mb-2 mt-4"
|
|
htmlFor={`related-item-history-${relatedItem.name}`}>History</label>
|
|
<textarea
|
|
id={`related-item-history-${relatedItem.name}`}
|
|
rows={3}
|
|
value={relatedItem.history}
|
|
onChange={(e) => handleElementChange('relatedItems', index, 'history', e.target.value)}
|
|
className="input-base"
|
|
></textarea>
|
|
<div className="mt-2">
|
|
<Button variant="danger" icon={Trash2}
|
|
onClick={() => handleRemoveElement('relatedItems', index)}>
|
|
Remove
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</details>
|
|
))}
|
|
<div className="flex space-x-2 items-center mt-2">
|
|
<select
|
|
className="input-base"
|
|
onChange={(e) => setNewRelatedItem({...newRelatedItem, name: e.target.value})}
|
|
value={newRelatedItem.name}
|
|
>
|
|
<option value="">Select Related Item</option>
|
|
{items.map((item) => (
|
|
<option key={item.id} value={item.name}>{item.name}</option>
|
|
))}
|
|
</select>
|
|
<select
|
|
className="input-base"
|
|
onChange={(e) => setNewRelatedItem({...newRelatedItem, type: e.target.value})}
|
|
value={newRelatedItem.type}
|
|
>
|
|
<option value="">Relation Type</option>
|
|
<option value="Related">Related</option>
|
|
<option value="Similar">Similar</option>
|
|
</select>
|
|
<Button variant="primary" icon={Plus} onClick={() => {
|
|
handleAddElement('relatedItems', {...newRelatedItem});
|
|
setNewRelatedItem({name: '', type: '', description: '', history: ''});
|
|
}}>
|
|
Add Related Item
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<div>
|
|
<div className="flex justify-between sticky top-0 z-10 bg-darkest-background py-4">
|
|
<input
|
|
type="text"
|
|
value={searchQuery}
|
|
onChange={(e) => setSearchQuery(e.target.value)}
|
|
className="input-base"
|
|
placeholder="Search Items"
|
|
/>
|
|
<div className="ml-4">
|
|
<Button variant="primary" icon={Plus} onClick={handleAddItem}>
|
|
Add New Item
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<h2 className="text-4xl font-['ADLaM_Display'] text-text-primary mb-6">Items</h2>
|
|
<div className="flex flex-wrap space-x-4">
|
|
{filteredItems.map((item) => (
|
|
<div key={item.id} onClick={() => handleItemClick(item)}
|
|
className="cursor-pointer bg-tertiary/90 backdrop-blur-sm p-4 rounded-xl shadow-lg hover:shadow-xl hover:scale-105 transition-all duration-200 border border-secondary/50">
|
|
<img src={item.image || 'https://via.placeholder.com/150'} alt={item.name}
|
|
className="w-full h-32 object-cover rounded-lg mb-2"/>
|
|
<h3 className="text-lg font-bold text-text-primary">{item.name}</h3>
|
|
<p className="text-muted">{item.description}</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</main>
|
|
);
|
|
}
|