Frontend to start building your own project in react, also you can check about backend in WebCrack and can always dm me
App.tsx
import { Route, Routes } from 'react-router-dom'
import Navbar from './components/Navbar'
import Home from './pages/Home'
import Gallery from './pages/Gallery'
import Search from './pages/Search'
import Studio from './pages/Studio'
import Artwork from './pages/Artwork'
import Profile from './pages/Profile'
import Favorites from './pages/Favorites'
import Cart from './pages/Cart'
import Checkout from './pages/Checkout'
import Login from './pages/Login'
import Register from './pages/Register'
import RequireAuth from './pages/RequireAuth'
import { useDispatch, useSelector } from 'react-redux'
import Logout from './pages/Logout'
import { useEffect } from 'react'
import { artworkAdd } from './redux/actions/artworkActions'
import type { RootState } from './redux'
import Auth from './pages/Auth'
import { favoriteAdd } from './redux/actions/favoriteActions'
function App() {
const dispatch = useDispatch()
const { isLogged, auth } = useSelector((state: RootState) => state.auth)
const isArtworkLoaded = useSelector((state: RootState) => state.artwork.isLoaded)
const isFavoriteLoaded = useSelector((state: RootState) => state.favorite.isLoaded)
useEffect(() => {
if (!isArtworkLoaded) {
fetch('http://localhost:8080/artwork')
.then((res) => res.json())
.then((data) => {
if (Array.isArray(data)) {
console.log(data)
data.forEach((artwork) => {
dispatch(artworkAdd(artwork))
})
}
})
.catch((err) => console.error(err))
}
if (isLogged && !isFavoriteLoaded && auth.user) {
fetch(`http://localhost:8080/user/${auth.user.id}/favorite`)
.then((res) => res.json())
.then((data) => {
if (Array.isArray(data)) {
console.log(data)
data.forEach((favorite) => {
dispatch(favoriteAdd(favorite))
})
}
})
.catch((err) => console.error(err))
}
}, [dispatch, isArtworkLoaded, auth.user, isLogged, isFavoriteLoaded])
return (
<>
<Navbar />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/gallery">
<Route index element={<Gallery />} />
<Route path=":artworkId" element={<Artwork />} />
</Route>
<Route path="/search" element={<Search />} />
<Route
path="/studio"
element={
<RequireAuth>
<Studio />
</RequireAuth>
}
/>
<Route
path="/favorites"
element={
<RequireAuth>
<Favorites />
</RequireAuth>
}
/>
<Route
path="/cart"
element={
<RequireAuth>
<Cart />
</RequireAuth>
}
/>
<Route
path="/checkout"
element={
<RequireAuth>
<Checkout />
</RequireAuth>
}
/>
<Route path="/auth" element={<Auth />}>
<Route path="login" element={<Login />} />
<Route path="register" element={<Register />} />
<Route path="logout" element={<Logout />} />
</Route>
<Route path="/profile">
<Route
index
element={
<RequireAuth>
<Profile />
</RequireAuth>
}
/>
{/* <Route path="edit" element={<Profile />} /> */}
<Route path=":userId" element={<Profile />} />
</Route>
{/* <Route
path="/settings"
element={
<RequireAuth>
<Settings />
</RequireAuth>
}
/> */}
</Routes>
</>
)
}
export default App
Main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import store from './redux/index.ts'
import App from './App.tsx'
import '@fontsource/roboto/400.css'
import '@fontsource/roboto/700.css'
import './styles.css'
ReactDOM.createRoot(document.getElementById('root')!).render(
<BrowserRouter>
<Provider store={store}>
<App />
</Provider>
</BrowserRouter>
)
Reducer example
import type { PayloadAction, Reducer } from '@reduxjs/toolkit'
import type { Artwork } from '../../types/database'
import { ArtworkActionTypes } from '../actions/artworkActions'
import type { CustomPayload } from '../../types/redux'
interface ArtworkReducer {
artworks: Artwork[]
isLoaded: boolean
}
const initialState: ArtworkReducer = {
artworks: [],
isLoaded: false
}
const artworkReducer: Reducer<ArtworkReducer, PayloadAction<CustomPayload<Artwork>, keyof typeof ArtworkActionTypes>> =
(state = initialState, action) => {
switch (action.type) {
case ArtworkActionTypes.ADD_ARTWORK: {
if (!action.payload.body) return state
return {
artworks: [...state.artworks, {
id: action.payload.body.id ?? state.artworks.length + 1,
artist: action.payload.body.artist,
category: action.payload.body.category,
description: action.payload.body.description,
image: action.payload.body.image,
orientation: action.payload.body.orientation,
price: action.payload.body.price,
style: action.payload.body.style,
theme: action.payload.body.theme,
title: action.payload.body.title,
stock: action.payload.body.stock,
hidden: action.payload.body.hidden
}],
isLoaded: true,
}
}
case ArtworkActionTypes.EDIT_ARTWORK: {
if (!state.isLoaded || !action.payload.id || !action.payload.body) return state
return {
...state,
artworks: state.artworks.map((artwork) => {
if (artwork.id === action.payload.id) {
return {
...artwork,
...action.payload.body
}
}
return artwork
})
}
}
case ArtworkActionTypes.REMOVE_ARTWORK: {
if (!state.isLoaded || !action.payload.id) return state
return {
...state,
artworks: state.artworks.filter((artwork) => artwork.id !== action.payload.id)
}
}
default: {
return state
}
}
}
export default artworkReducer
Home example
import Button from '../../components/Button'
import HeroGallery from './components/HeroGallery'
import styles from './styles.module.css'
export default function Home() {
return (
<main>
<section className={styles.heroSection}>
<HeroGallery>
<h1 className={styles.heroTitle}>
DISCOVER STUNNING <span>AI-GENERATED</span> IMAGES
</h1>
<p className={styles.heroText}>
Unlock a world of creativity with our unique collection of
AI-generated images. Each image is crafted with precision and
creativity, offering a fresh perspective on digital art.
</p>
<Button to="/gallery">EXPLORE GALLERY</Button>
</HeroGallery>
</section>
<section className={styles.aiArtStepsSection}>
<h2 className={styles.aiArtStepsTitle}><span>CREATE</span> YOUR OWN AI ART</h2>
<div className={styles.aiArtStepsDataContainer}>
<div className={styles.aiArtStepsData}>
<ol className={styles.aiArtStepsList}>
<li><span>1. Choose Your Base Image:</span> Select an image from our library as the base for your creation.</li>
<li><span>2. Customize Your Art:</span> Use our intuitive tools to tweak parameters such as colors, styles, patterns, and more to personalize your art piece.</li>
<li><span>3. Preview and Adjust:</span> Preview your creation in real-time and make adjustments until you're satisfied with the result.</li>
<li><span>4. Sell Your Art:</span> Once you're happy with your creation, you can choose to sell it in our marketplace and earn from your artistry</li>
</ol>
<p>Create an account today and start expressing your creativity with AI-generated art!</p>
<Button to='/studio'>GET STARTED</Button>
</div>
<div className={styles.aiArtStepsVideoContainer}>
<video autoPlay loop muted>
<source src='/assets/video/studio-demo.mp4' type='video/mp4' />
</video>
</div>
</div>
</section>
</main>
)
}
Button example
import type { ButtonHTMLAttributes, DetailedHTMLProps, MouseEvent } from 'react'
import { useNavigate } from 'react-router-dom'
import styles from './styles.module.css'
interface Props
extends DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
to?: string
}
export default function Button({ children, onClick, to, ...buttonProps }: Props) {
const navigate = useNavigate()
const handleClick = (e: MouseEvent<HTMLButtonElement>) => {
if (onClick !== undefined) {
onClick(e)
}
if (to !== undefined) {
navigate(to)
}
}
return (
<button className={styles.button} onClick={(e) => handleClick(e)} {...buttonProps}>
{children}
</button>
)
}
Button styles
.button {
display: flex;
align-items: center;
gap: 8px;
padding: 8px;
border: 1px solid var(--color-black);
background-color: #FFFFFF;
cursor: pointer;
}
Form example
// components/AddProductForm.tsx
import React, { useState } from 'react';
interface Product {
id: number;
nombre: string;
precio: number;
}
const AddProductForm: React.FC<{ onAddProduct: (product: Product) => void }> = ({ onAddProduct }) => {
const [id, setId] = useState<number>(0);
const [nombre, setNombre] = useState<string>('');
const [precio, setPrecio] = useState<number>(0);
const handleIdChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setId(Number(event.target.value));
};
const handleNombreChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setNombre(event.target.value);
};
const handlePrecioChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setPrecio(Number(event.target.value));
};
const handleSubmit = async (event: React.FormEvent) => {
event.preventDefault();
// Validación simple, asegúrate de implementar validaciones más robustas según tus requisitos
if (!nombre || precio <= 0) {
alert('Por favor ingresa un nombre y un precio válido.');
return;
}
// Crear el objeto de producto
const product: Product = { id, nombre, precio };
// Llamar al callback para agregar el producto
onAddProduct(product);
// Limpiar el formulario después de agregar el producto
setId(0);
setNombre('');
setPrecio(0);
};
return (
<form onSubmit={handleSubmit}>
<label>
ID:
<input type="number" value={id} onChange={handleIdChange} />
</label>
<label>
Nombre:
<input type="text" value={nombre} onChange={handleNombreChange} />
</label>
<label>
Precio:
<input type="number" value={precio} onChange={handlePrecioChange} />
</label>
<button type="submit">Agregar Producto</button>
</form>
);
};
export default AddProductForm;
This is a frontend example project where you can feel free of using it. You can add all you can and let me know about your own projects
New contributor
WebCrack is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
1