328 lines
19 KiB
TypeScript
328 lines
19 KiB
TypeScript
'use client';
|
|
import React, {useState} from 'react';
|
|
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
|
import {faArrowLeft} from '@fortawesome/free-solid-svg-icons';
|
|
|
|
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-gray-900 py-4">
|
|
<button onClick={() => setSelectedItem(null)}
|
|
className="flex items-center gap-2 text-text-primary bg-secondary/50 hover:bg-secondary px-4 py-2 rounded-xl transition-all duration-200 hover:scale-105 shadow-md">
|
|
<FontAwesomeIcon icon={faArrowLeft} className="mr-2 w-5 h-5"/> Back
|
|
</button>
|
|
<h2 className="text-3xl font-['ADLaM_Display'] text-center text-text-primary">{selectedItem.name}</h2>
|
|
<button onClick={handleSaveItem}
|
|
className="bg-primary hover:bg-primary-dark text-text-primary font-semibold py-2.5 px-6 rounded-xl shadow-md hover:shadow-lg hover:scale-105 transition-all duration-200">
|
|
Save Item
|
|
</button>
|
|
</div>
|
|
<div className="bg-gray-700 rounded-lg p-8 shadow-lg space-y-4">
|
|
<div>
|
|
<label className="block text-white mb-2" htmlFor="name">Name</label>
|
|
<input
|
|
type="text"
|
|
id="name"
|
|
value={selectedItem.name}
|
|
onChange={(e) => handleItemChange('name', e.target.value)}
|
|
className="w-full px-4 py-2.5 rounded-xl bg-secondary/50 text-text-primary border border-secondary/50 outline-none hover:bg-secondary hover:border-secondary focus:border-primary focus:ring-4 focus:ring-primary/20 transition-all duration-200"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-white mb-2" htmlFor="description">Description</label>
|
|
<textarea
|
|
id="description"
|
|
rows={4}
|
|
value={selectedItem.description}
|
|
onChange={(e) => handleItemChange('description', e.target.value)}
|
|
className="w-full px-4 py-2.5 rounded-xl bg-secondary/50 text-text-primary border border-secondary/50 outline-none hover:bg-secondary hover:border-secondary focus:border-primary focus:ring-4 focus:ring-primary/20 transition-all duration-200"
|
|
></textarea>
|
|
</div>
|
|
<div>
|
|
<label className="block text-white mb-2" htmlFor="history">History</label>
|
|
<textarea
|
|
id="history"
|
|
rows={4}
|
|
value={selectedItem.history}
|
|
onChange={(e) => handleItemChange('history', e.target.value)}
|
|
className="w-full px-4 py-2.5 rounded-xl bg-secondary/50 text-text-primary border border-secondary/50 outline-none hover:bg-secondary hover:border-secondary focus:border-primary focus:ring-4 focus:ring-primary/20 transition-all duration-200"
|
|
></textarea>
|
|
</div>
|
|
<div>
|
|
<label className="block text-white mb-2" htmlFor="location">Location</label>
|
|
<select
|
|
id="location"
|
|
value={selectedItem.location}
|
|
onChange={(e) => handleItemChange('location', e.target.value)}
|
|
className="w-full px-4 py-2.5 rounded-xl bg-secondary/50 text-text-primary border border-secondary/50 outline-none hover:bg-secondary hover:border-secondary focus:border-primary focus:ring-4 focus:ring-primary/20 transition-all duration-200"
|
|
>
|
|
<option value="">Select Location</option>
|
|
<option value="Castle">Castle</option>
|
|
<option value="Fortress">Fortress</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label className="block text-white mb-2" htmlFor="ownedBy">Owned By</label>
|
|
<select
|
|
id="ownedBy"
|
|
value={selectedItem.ownedBy}
|
|
onChange={(e) => handleItemChange('ownedBy', e.target.value)}
|
|
className="w-full px-4 py-2.5 rounded-xl bg-secondary/50 text-text-primary border border-secondary/50 outline-none hover:bg-secondary hover:border-secondary focus:border-primary focus:ring-4 focus:ring-primary/20 transition-all duration-200"
|
|
>
|
|
<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-white mb-2" htmlFor="functionality">Functionality</label>
|
|
<textarea
|
|
id="functionality"
|
|
rows={4}
|
|
value={selectedItem.functionality}
|
|
onChange={(e) => handleItemChange('functionality', e.target.value)}
|
|
className="w-full px-4 py-2.5 rounded-xl bg-secondary/50 text-text-primary border border-secondary/50 outline-none hover:bg-secondary hover:border-secondary focus:border-primary focus:ring-4 focus:ring-primary/20 transition-all duration-200"
|
|
></textarea>
|
|
</div>
|
|
<div>
|
|
<label className="block text-white mb-2" htmlFor="image">Image URL</label>
|
|
<input
|
|
type="text"
|
|
id="image"
|
|
value={selectedItem.image}
|
|
onChange={(e) => handleItemChange('image', e.target.value)}
|
|
className="w-full px-4 py-2.5 rounded-xl bg-secondary/50 text-text-primary border border-secondary/50 outline-none hover:bg-secondary hover:border-secondary focus:border-primary focus:ring-4 focus:ring-primary/20 transition-all duration-200"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="bg-gray-700 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-white cursor-pointer">{relatedItem.name}</summary>
|
|
<div className="mt-2">
|
|
<label className="block text-white 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="w-full px-4 py-2.5 rounded-xl bg-secondary/50 text-text-primary border border-secondary/50 outline-none hover:bg-secondary hover:border-secondary focus:border-primary focus:ring-4 focus:ring-primary/20 transition-all duration-200"
|
|
></textarea>
|
|
<label className="block text-white 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="w-full px-4 py-2.5 rounded-xl bg-secondary/50 text-text-primary border border-secondary/50 outline-none hover:bg-secondary hover:border-secondary focus:border-primary focus:ring-4 focus:ring-primary/20 transition-all duration-200"
|
|
></textarea>
|
|
<button
|
|
type="button"
|
|
onClick={() => handleRemoveElement('relatedItems', index)}
|
|
className="bg-error/90 hover:bg-error text-text-primary font-semibold py-2 px-4 rounded-xl shadow-md hover:shadow-lg hover:scale-105 transition-all duration-200 mt-2"
|
|
>
|
|
Remove
|
|
</button>
|
|
</div>
|
|
</details>
|
|
))}
|
|
<div className="flex space-x-2 items-center mt-2">
|
|
<select
|
|
className="w-full px-4 py-2.5 rounded-xl bg-secondary/50 text-text-primary border border-secondary/50 outline-none hover:bg-secondary hover:border-secondary focus:border-primary focus:ring-4 focus:ring-primary/20 transition-all duration-200"
|
|
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="w-full px-4 py-2.5 rounded-xl bg-secondary/50 text-text-primary border border-secondary/50 outline-none hover:bg-secondary hover:border-secondary focus:border-primary focus:ring-4 focus:ring-primary/20 transition-all duration-200"
|
|
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>
|
|
{/* Add more relation types as needed */}
|
|
</select>
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
handleAddElement('relatedItems', {...newRelatedItem});
|
|
setNewRelatedItem({name: '', type: '', description: '', history: ''});
|
|
}}
|
|
className="bg-primary hover:bg-primary-dark text-text-primary font-semibold py-2.5 px-5 rounded-xl shadow-md hover:shadow-lg hover:scale-105 transition-all duration-200"
|
|
>
|
|
Add Related Item
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<div>
|
|
<div className="flex justify-between sticky top-0 z-10 bg-gray-900 py-4">
|
|
<input
|
|
type="text"
|
|
value={searchQuery}
|
|
onChange={(e) => setSearchQuery(e.target.value)}
|
|
className="w-full px-4 py-2.5 rounded-xl bg-secondary/50 text-text-primary border border-secondary/50 outline-none hover:bg-secondary hover:border-secondary focus:border-primary focus:ring-4 focus:ring-primary/20 transition-all duration-200"
|
|
placeholder="Search Items"
|
|
/>
|
|
<button
|
|
type="button"
|
|
onClick={handleAddItem}
|
|
className="bg-primary hover:bg-primary-dark text-text-primary font-semibold py-2.5 px-5 rounded-xl ml-4 shadow-md hover:shadow-lg hover:scale-105 transition-all duration-200"
|
|
>
|
|
Add New Item
|
|
</button>
|
|
</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>
|
|
);
|
|
}
|