Feature: user upload artwork
This commit is contained in:
@@ -1,81 +1,107 @@
|
||||
import {useState, useEffect} from 'react';
|
||||
import type {Artwork} from '@/types';
|
||||
|
||||
const SAMPLE_ARTWORKS: Artwork[] = [
|
||||
{
|
||||
id: '1',
|
||||
title: 'Dragon 1',
|
||||
description: '',
|
||||
imageUrl: '/gallery/ArtFixture_2.jpg?inline',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: 'Dragon 2',
|
||||
description: '',
|
||||
imageUrl: '/gallery/ArtFixture_3.jpg?inline',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: 'Dragon 3',
|
||||
description: '',
|
||||
imageUrl: '/gallery/ArtFixture_4.jpg?inline',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
title: 'Abstract Emotions',
|
||||
description: '',
|
||||
imageUrl: '/gallery/ArtFixture_5.jpg?inline',
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
title: 'Humorous',
|
||||
description: '',
|
||||
imageUrl: '/gallery/ArtFixture_6.png?inline',
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
title: 'Rainbows',
|
||||
description: '',
|
||||
imageUrl: '/gallery/ArtFixture_7.jpg?inline',
|
||||
}
|
||||
];
|
||||
interface ArtworkResponse {
|
||||
id: string;
|
||||
title: string;
|
||||
filename: string;
|
||||
mimetype: string;
|
||||
size: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export const useArtwork = () => {
|
||||
const [artworks, setArtworks] = useState<Artwork[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// Load from localStorage or use sample data
|
||||
const stored = localStorage.getItem('artworks');
|
||||
if (stored) {
|
||||
setArtworks(JSON.parse(stored));
|
||||
} else {
|
||||
setArtworks(SAMPLE_ARTWORKS);
|
||||
localStorage.setItem('artworks', JSON.stringify(SAMPLE_ARTWORKS));
|
||||
const fetchArtworks = async () => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const response = await fetch('/api/artworks');
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch artworks');
|
||||
}
|
||||
const data: ArtworkResponse[] = await response.json();
|
||||
|
||||
// Transform backend data to frontend format
|
||||
const transformedArtworks: Artwork[] = data.map(artwork => ({
|
||||
id: artwork.id,
|
||||
title: artwork.title,
|
||||
imageUrl: `/api/artworks/${artwork.id}/image`
|
||||
}));
|
||||
|
||||
setArtworks(transformedArtworks);
|
||||
} catch (err) {
|
||||
console.error('Error fetching artworks:', err);
|
||||
setError(err instanceof Error ? err.message : 'Failed to load artworks');
|
||||
setArtworks([]);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
setLoading(false);
|
||||
}, []);
|
||||
|
||||
const addArtwork = (artwork: Omit<Artwork, 'id'>) => {
|
||||
const newArtwork: Artwork = {
|
||||
...artwork,
|
||||
id: Date.now().toString()
|
||||
};
|
||||
const updated = [...artworks, newArtwork];
|
||||
setArtworks(updated);
|
||||
localStorage.setItem('artworks', JSON.stringify(updated));
|
||||
};
|
||||
|
||||
const deleteArtwork = (id: string) => {
|
||||
const updated = artworks.filter(art => art.id !== id);
|
||||
setArtworks(updated);
|
||||
localStorage.setItem('artworks', JSON.stringify(updated));
|
||||
useEffect(() => {
|
||||
fetchArtworks();
|
||||
}, []);
|
||||
|
||||
const addArtwork = async (artwork: Omit<Artwork, 'id'>, file: File) => {
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('title', artwork.title);
|
||||
formData.append('image', file);
|
||||
|
||||
const response = await fetch('/api/artworks', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
throw new Error(errorData.message || 'Failed to upload artwork');
|
||||
}
|
||||
|
||||
const newArtworkData: ArtworkResponse = await response.json();
|
||||
|
||||
const newArtwork: Artwork = {
|
||||
id: newArtworkData.id,
|
||||
title: newArtworkData.title,
|
||||
imageUrl: `/api/artworks/${newArtworkData.id}/image`
|
||||
};
|
||||
|
||||
setArtworks(prev => [...prev, newArtwork]);
|
||||
return newArtwork;
|
||||
} catch (err) {
|
||||
console.error('Error adding artwork:', err);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteArtwork = async (id: string) => {
|
||||
try {
|
||||
const response = await fetch(`/api/artworks/${id}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to delete artwork');
|
||||
}
|
||||
|
||||
setArtworks(prev => prev.filter(art => art.id !== id));
|
||||
} catch (err) {
|
||||
console.error('Error deleting artwork:', err);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
artworks,
|
||||
loading,
|
||||
error,
|
||||
addArtwork,
|
||||
deleteArtwork
|
||||
deleteArtwork,
|
||||
refetch: fetchArtworks
|
||||
};
|
||||
};
|
||||
|
||||
@@ -19,12 +19,12 @@ export const useAuth = () => {
|
||||
const response = await fetch('/api/users/login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username,
|
||||
password,
|
||||
}),
|
||||
password
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -32,7 +32,7 @@ export const useAuth = () => {
|
||||
}
|
||||
|
||||
const responseData = await response.json();
|
||||
|
||||
|
||||
if (responseData.status === 'ok') {
|
||||
setUser({username, isAuthenticated: true});
|
||||
localStorage.setItem('user', JSON.stringify({username, isAuthenticated: true}));
|
||||
|
||||
Reference in New Issue
Block a user