Documentation
Welcome to my documentation page. Here, you'll find reusable code snippets and explanations for various projects and technologies I work with.
My Code Library
Learning to Fetch data from an API (Lesson 6) Location components(folder) -> ProductList.tsx(file)
import { TypeFetchedProduct } from '@/actions/Products'
import Image from 'next/image'
import Link from 'next/link'
import React from 'react'
export default function Product({product}:{product:TypeFetchedProduct}) {
return (
<Link href={"/"} className='flex items-center gap-3 hover:bg-blue-100 rounded-md px-4 py-2 transition-all hover:-translate-y-1 duration-500'>
<Image
src={product.imageUrl}
width={500}
height={500}
alt={product.name}
className='w-16 h-16 rounded-lg'
/>
<div>
<h2 className='text-blue-700'>{product.imageUrl}</h2>
<div className="flex items-center justify-between">
<p><span>Price:</span>${product.price}</p>
<p><span>Stock:</span>{product.stock}items</p>
</div>
</div>
</Link>
)
}
Then data passes through the ProductList direct to the actual Product.
Learning to Fetch data from an API (Lesson 5) Location components(folder) -> ProductList.tsx(file)
import React from 'react'
import Product from './Product'
import { TypeFetchedProduct } from '@/actions/Products'
export default function ProductList({ products }: { products: TypeFetchedProduct[] }) {
return (
<div className='space-y-3'>
{
products.map((product)=>{
return(
<Product key={product.id} product={product}/>
)
})
}
</div>
)
}
The data passes through the StorePage then to the Product list.
Learning to Fetch data from an API (Lesson 4) Location components(folder) -> StorePage.tsx(file)
import React from 'react'
import Header from './Header'
import ProductList from './ProductList'
import ProductDetail from './ProductDetail'
import { TypeFetchedProduct } from '@/actions/Products'
export default function StorePage({receivedProducts}:{receivedProducts:TypeFetchedProduct[]}) {
return (
<div className='min-h-screen bg-gradient-to-r from-blue-600 to-blue-950 py-8 px-8'>
<div className="rounded-lg bg-blue-100 min-h-screen">
<Header/>
<main className='grid grid-cols-12 bg-gray-50 min-h-screen'>
<div className='col-span-4 pt-3'>
<ProductList products={receivedProducts}/>
</div>
<div className='col-span-8 bg-gray-100'>
<ProductDetail/>
</div>
</main>
</div>
</div>
)
}
The data passes through the props. to the StorePage.
Learning to Fetch data from an API (Lesson 3) Location app(folder) -> page.tsx(file)
import { getProducts } from '@/actions/Products'
import StorePage from '@/components/StorePage'
import React from 'react'
export default async function page() {
const fetchedProducts = (await getProducts()) || []
return (
<div>
{/* Show something incase there are no products */}
{
fetchedProducts && fetchedProducts.length>0?(<StorePage receivedProducts={fetchedProducts}/>):(<div><h2>No Products</h2></div>)
}
</div>
)
}
This is the page where we are going to fetch the data. Make sure it is clean because it is going to be server side.
Learning to Fetch data from an API (Lesson 2) actions(folder) -> products.ts(file)
"use server"
// Then lastly we have to define the types for the data we are fetching.
//Right now it has any which is dangerous
//Defining the types for that data is so good because it is going to help us all around.
export interface TypeFetchedProduct{
id:string,
imageUrl:string,
stock:number,
name:string,
price:number,
}
const API = "https://inventory-app-ten-gilt.vercel.app/api/v1/products"
export async function getProducts(){
try {
//send a response
const response = await fetch(API)
//the result obtained, convert it into json
const result = await response.json()
//return the result which has been converted
// const fetchedProducts = result.data;
//but just above the data is too much and we don't want all that data to come just a few.
//so here we only get that particular thing we want from the data.
const fetchedProducts = result.data.map((fetchedProduct:any)=>{
return{
id:fetchedProduct.id,
imageUrl:fetchedProduct.productThumbnail,
stock:fetchedProduct.stockQty,
name:fetchedProduct.name,
price:fetchedProduct.productPrice,
}
})
return fetchedProducts as TypeFetchedProduct[]
// return result
} catch (error) {
console.log(error)
return[]
}
}
This is the second lesson of fetching data from an API.
Learning to Fetch data from an API (Lesson 1) actions(folder) -> products.ts(file)
"use server"
const API = "https://inventory-app-ten-gilt.vercel.app/api/v1/products"
export async function getProducts(){
try {
//send a response
const response = await fetch(API)
//the result obtained, convert it into json
const result = await response.json()
//return the result which has been converted
return result
} catch (error) {
console.log(error)
return[]
}
}
This is a the introduction lesson to fetch data from an api.
Product Detail (Details about a particular product)
import Image from 'next/image'
import React from 'react'
import { Bookmark } from 'lucide-react'
import { Button } from './ui/button'
export default function ProductDetail() {
return (
<div className='relative'>
<Image
src={"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxAQDxAPDxAPEA8PDQ0NDQ8PDw8PDQ4PFREWFhURFRUYHiggGBolGxUVITEhJSkrLi8uFx85ODMtNygtLisBCgoKDg0OFQ8QFysdHR0tLS0tLSstKy0rKy0tLS0tKysrLS0rKy0tLS0tLS0tKy0tLSstLS0tLS0tLS0rKystLf/AABEIAKgBKwMBEQACEQEDEQH/xAAbAAACAwEBAQAAAAAAAAAAAAAAAwECBAUGB//EAE0QAAEDAgIECQULCQcFAAAAAAEAAgMEERIhBQYxQQcTUWFxgZGh0RUik7HBFDJCQ1JUYnKCktIWIyQzRFOi0/AXNHODssLiY6Ok1OH/xAAaAQEBAQEBAQEAAAAAAAAAAAAAAQIDBAUG/8QANBEBAAIBAgQDBQcEAwEAAAAAAAECEQMSEyExUQQFQRRSYXGRIjIzgaGx0SNi4fBCQ8EV/9oADAMBAAIRAxEAPwDy7SvK/QGBGlkEgqKlVVgguEVdoRYMARpYIqwRUoIuqJRUo1CUVIQSEawlDAQkImE2VXCFEBQVKJhBRMIsiTCFGQQgWQiYUcEQpwRkpyMqEIihRFSiKFEQqLhQXBRVgirhFWRVmoq4RVwirYkVOMIuU40MpxKqkORqEhyKMSqpD0VONFTiRRiRBdBIKAxKgxKCMSCMSIsoBEQozKCiKlELcEZKcEZkpwRkohEVKIWVUUKIi6C4UFwirBBdpRpcIqzUWDAEaXCK8vrJpCpbUNigfI0cU12GLJznFzhckZncLL16GjbUj7MZfD8frTXVmJtiHJl0jXsNnzVbTts58jTblsV39k1eux4uN/cSdNVY/aan0r/FZnQvHWq8WfeR5dqvnVR6WRYmsx6NcS3eR5dqfnVR6WTxWcG+3eUeXan51Uelk8UOJf3pHl2p+dVPppPFOS8S/vSq7TlV87qPTS+KhxL+9P1V8tVXzup9NN4qnEv3n6jy1VfO6n003iocS/efqlum6nfVVPp5vFMHEv70reW6n51Venm8UxBxL+9I8uVPzqq9PN4piDiX96R5cqfnVV6ebxV5HEv70ryaXqm2xVNULi4BqJb25xiyW76U0xujGWY1bT0tKnlyp+dVXp5vFY5Lvv3kHTdR86qvTzeKmIXiW7y+haAqXS0sMjzdzmEOdvJDi2558lxvGJfovBXm+jWZdELD1CyJhBaozMKOaiFuCIU4IxJLgjMllELcqhbkZUciKohgUVYFFXCELBFMCNGNRYMARqFwEaecqzh0kxwNiynjkBN7XbLcbOhfc8njN7VxnNZ/eH5rzaP6n0/YawSiaQPy94GYbudaxJ2kC+0r9Fo6M1rNZj9nxb2xMYl5+emXDV0MutNRhlgsvnavhnprdndGvBfQmHWLKELhNMNZQsYAsqEAgEAgZFCXZ7Gja45NHX7F1po2tz6R39GZtEGca1nvM3fvCNn1Ru6dvQt8Sun+H17/AMR/sptm33voQTfM5k5k7yuEzM85bQoBB9N1PzoouYzD/uuXG/V+j8u/Aj83cAXN7sAhEwqjKCokluCM4JcEYkpwRmSXIyU5VC3IzKhRFEQwKCwRV2o0Y1FXCKa1GoMCNGBGnn6iLFpWJhLQH0zQS8lrP1jtp3DJfa8nvs1Jt/bP7w/L+dxabTFevL9ltLyRkMLInROwuEl74HOByLL821fp9C1833WiY5Y7/m/OaddSsYvOfi4szgt3tD0ViWGZwXi1LQ9NIlikIXg1Zh6KkOXh1MOsFleWzSFzkWYwnIAnoC3TTvecVjJMxHUw05HvrDvK7+x2iM3nDHEieiWUxIuB5u9zvNYOsq+yzjOOXeeUE3jok4G/9Q9YjHtPcsTOnTp9qfpH8yfan4fuVLKXbTs2AZNHQNy5Xva/WWorEdFFhoIBAIPpupGdEzmklH8V/auN+r9H5Z+B+cu/hXN7wWqCpCMqEKMyo4IyS4IxJTgjMkvVZkhyMluRktyIoiGBQMaUWFwjS7QimAIpjUbgwBFgwI085pSLFpBg5aPLqkK+35Ljjc+0vzfm9Zm84+BGkuMv57RssC0Bo7Av08acUjERyfAtumftONKb5XLTz7F5bfa5ZxLvWMfFkngkG1pI5QLheLVprV9M/J3pek+rIQ47j2LwzGpb/jLvyMZRyO2NPZklfB61/RmdakerVDoZ7tpA5hme5emnlUz9+2HG3i6+kZdGLV/CLuY63LJ+bZ3r2U8BoU683KdfVt0jAmELBYyD6sLcR7dneutr6dIxH6FdO087S501W0fq4gD8uQ8Y7pA2DvXg1NaY+5WI+M85emKRjnLFNI55u5xdyX2Do5F87Ui95zeZl1rER0KsuWxrKLKbTIsptMiybTIsm0ymyu0y+lcHwvRdE8g/hafavLqRzfovKZ/oz8/4enwLnL6armqJMFEKJMKkKMSU5GZKeEYkl4RiSHqsyQ5GS3IzJTkRRVDAsizSimNKKc1GjAjUGtCNQYEahYIrgaRJGkISBf8ARnjscV9nyef60fm/O+cTtvn5OuOLkGF4t05L9TumOcPiTqVtys4+lNCAc7TsKYpqxhzn7HOsvOze6Ka+BzsG8bQOkL52vXX8PzpOYda8HX5Wjm62gq8yAENa97QXPic1ri5o2vaD74DeNo27L26aHjOJG2/Ke6aunOnia9HsNG1FJMB5rIXn5LWhhPZcJq01K84nMN0vF47NFXoh7gcLnkfQefUFwjXx1bmmXmtIavuBJs4nnzK711qz1ee+naOji1OjHDa09i6YpZiL2jrDny0a520Idq6zLJTELz30HaurlndEvNbRdYsoWLlOk1lGFY4a5GBOGZWEa1GjKbjI6UuNgNmbtgDRyknIDpVnTiOpnPR9B4OW/o0wBvarfYi9j+bjzHYvk6v3uT9J5R+Fb5/+PWBq5PrBzFBnexRmS3BRkoozgpyMzBEgRzlnejEkuCMSU5GZKciFqsrhZVcIq7UU5hRqDmo1BrUahcIqUaeT1urZIKiGWJ2F4ieL4WuyLsxZwIK9Ojeac6ziXxPMoidWPkyU+u04sJI4JBv8wscfum3cvfTzDWr1nL5c6NOzp0+udM4Wlhmjvt4tzZW9hsvXTzX3oZnRhqZX0Mtw2eI/RlDoHDoLhh7176eaaVo5zj5uFvCQyVGrhuJaR9yCHtwuAcHDMOY5uRPQk00tTnWcft/hdt4jE83QoKmKc8VVn3HWbBUYcNPOf+q3Y130hYcqu/U0vTMf70eG9L6U5p0/Z1HvrqAgTR44trXg4oy3la8bAr/R145TiWqeKtGMunBrFBLbaCcsLhiz6Vwnwlo6S9PtVJxB7oYZBsb3t9a57L1bmYlzKvV5jtjT2LpXUtHq4WiJ9HCrNXCNgcvTXUz1ee19vpLkzaCdyLpw62ZjxsR1ZzoN3IexT2Ws+rpHjoHkIgXwm3Kch2p7LSD26J5ZZzRNxYG3kftDIgXu6cty4X4dXopa9+kfVlqHxx++ILv3cTg4/ak2D7N+pfM1vF1jlX/fzeuml3c6epc/LJrQbhjcmA8vKTzm5Xzb6lr9XaIw+icF5vTTjknae2MeC5Wff8on7F/nD2mFc31xZQKkapIzvaoks7gjnJTgjEkPUc5Z3KsSS9GJIejJL0ZlREXUFmlVV2lRTmFGoOYUbiT2I1C4RpYIrxmv48+H/Df/AKgu9Oj43mX4kfL/ANl5NbfOCAQXilcw3Y5zTytJae0KxaY5xI6LNP1FsL3iZoywzNEn8R84dq9Wn43Wp0tn582ZpEuxobXeenGBhc2PfC609MeiN+belrgV6I8dp3/Epie8PPfwtLOwzWTR0+csPESb3QOvGTylkmEj0hXrp4uvpqRPz5S8N/L5j7ufr/OT218QtxEsThuuJw7sFx3r1V1t3afzh5beC1PW0/78j2aYqB71pd9UOKTOfRI8Lqx0vK/lmsdl7neelpA7ys7qx2bnweveMTef0/gmSvnHv20sPPNUU7O4uJWbeKpXraGK+TzM85lhqdLsb+sr6dv0aZkk7u1rWt71wt5jSOk5erT8opHVxa3T9P8AAjnqHfKqZOLjB+pGbn768mp5jafuw9+n4PTp0hx63S80oLCQyMm/FQtEUXWG++PO65XivrXv1l6YrEdGBclCK+kcE+cdUOR8B7Q8exZs+15RPK8fJ7wxrD7SpjUwFvasjNIFAh7UYkh4Uc5Z5AjnLM9VzlnejEkPKMkvVZktGVwVFXBRV2lFNYo1B7Eag9pRswI0kKrDx/CAPOg+pL/qau2n0fH8z/Er8nkVt80IBAIBAIBAIBAIBAIBAIBAIr6RwPC5qx9GmPfKpL6/lM87/k+lOiWZfaiSnxrMrlnkastMkjVmRneFGJZpEYlnkCOcskirlLM9GJIejEkuVQtEWBURcFFMaUaNajUHMKjUHsRqDmhG4MaFWoeP4QxnT/Vm9bF10+j4/mf36/J45dHzAgEAgEAgEAgEAgEAgEAgEAg+j8DJ/PVY5YYj2Pd4qS+p5ZOL2+T6m5ikvtRYp7FmWolmlasy6QxytWZVklCyzMMsgRiWWRHOWSRVxsyvKMSzvKrEkuKMyWSjKQVBcFGjGlFg5hRqDmo1DRGo3DQxG4NAVbh5DhEb/dzzTDvYuun0l8jzT71PlLxa6PlBAIBAIBAIBAIBAIBAIBAIBFfSOBDOsqW8tHfslZ4o9vgbYvPyfYHwWUmH14uzyxrMutbMUrFiXesscoWXRjlaoksUoUYlimVcrMUpRylmkKOUsryqxJDyjEl3RAHKBjXI1k1pRo5hRT2FGoao1HSGliNw0MCOkPMa7Ub530kMdsckr42XNhiIba5XbS9XyPNetPzc6Hg6rnuc0GnxMIa8cdctJFwDYci6xz6PlTWYiJmOrSOC3SG91MP8134VdsosOCuv/e0g6ZJf5abZFm8FVbvnpB0PmP8AsTaGHgsqACXVMAABJs2Q2A6lYpM8kmcRlNHwYPlYHsrIi118J4qTO177bchVvpTWds9WaXi9YtXpLVHwRSO/bI+qF34lna2tPwSGNhe6uGFtr4aZzjttsxqWxWMytYzOIR/ZdGH8W6uOPCH4RT2u3mu7uV2wireDin8z9JqHcY4sBbCwBpG91zkE0431m3OPhPVm87ZiOueyo1ApcL3Y648XMYSOLjaX2NsbcjdvOutdGJnGWL6u2M4mWtnBvRl7mGSsswNOM8SI33vk04c7Wz6VmdOIiJy1F82muOh/9mlAM+OqzzY4Rf8AgU2w2Bwf6OBILqjI2zniAIte4y6k2wJ/IjRYBuJL3AGKpbnle+XPkm2AHVLRIB81t8LiMVYRdw2N2788+ZSYiPRMtWoFDTwabMdLhEb9Eve8Nl44CXj2YhiudwCk49Hp8NOLy+pSxrL6dbMUzFmXprZgmasS9NZYZmrEu8MMzVCWGYKMy586rjZhlRxlklKrlLLIUYkhxRlS6I7HkyP6XauO+Xr4NQNHM5Xdo8E3ycGqwoW8ru5N8nBqsKQcp7k3yvChcU4G8pvleHC4Fk3yu2IXEpHJ3pulVhWOG5vervXOHM0wyqldTy0sJllppxJZjHPAyyLgN1wvRoTM5fI80tnZn4tQ0prAdlCBmTlTPbmdpzcvRGY6Q+TNonrINbrHYn3KGja48VGAAN5u5OZujuo6r1gO+mH+fo7+YrzN0K21gd8fAOifR3sunNN0JFFrAdtTD6WlPqanM3ws3Q+ntgq4wPouy/hjT7Rugfk9p07a3s91n1QqYk3wr+SmmjtrnDo8oj1Qq4k3wu/U3SjrX0hI2zQHedpI3I35tCYk3wr+Q9cffaSk/wDK9pCbZTeqdRag++0m/wDi/wB0oU2yb1DqE4++0k49UJ9dSm03lf2ewn32kAfsUn/sq7TeYzg8pNhr8+QNpP5pTab12cHtAT/f3AAEk4YXdzSU2G8xvB9ozfpF56GM8E2Qb57PVaoanQaNn9108slQ4wPY1jjG1j2vsbhwHMM0mrppa2LRl0ZNfmXINNI0gkEGRtwRtByXlnWiPR96mjyzEs7tdmH4h/32+Ck60dnaNPHqRJrWw/FP+81ZnVjs7VnDO/WNh+Lf2tWd7rGozv02w/Af2tU3rxfgzyaTafgu7k3MzdlkqQdx7k3sTOWWTNXfDnNZkh8JKb2J05JdRuO8d6b4Z4UlOoH8re9N8MzoyodHP5W9/gm+E4NnfXF7EIC6AugLhUyguCiKkhUVJCI72pMtql7flwu7QQfFerw085h8nzWuaVt2l6DWWolZSySQvLHsMbsQaHHDjAdkenuXtfDh4l2sNYTlUyc+FjgBz7UVV+nKwnzaiovlk3jgBlnvTAq7S9UTZtTVuJ+CXTDoG1BSTSNRcAVFXiz81z3Hktt8EFHVswyMtTj2EPe1w2G+3f1IKSySAWe6fFkM3sINztzzG5AtxIb54ebgEEPZYC+/f6kEObZvnNvmSCJMx0i/cghrABcgOb8EccQRcW58svUgGEbThcOR0zwR/XsQTG4HznFhsAMLpnYhnuQQHNJLiYwfkueSTnkQf62oqWFpzJjBzyOeLZmD/W9EALb3PFC1wAWEtcCOnlRQXA7oeY8S4i33kHq9TdL/ALLI4Ha6A2LRbaY8+0dfMizC2t2i/wBqjHIJwOwSew9XOvJr6f8Ayh9by7xX/Vb8v4eXDgvI+xkYghlN0XIuhlN0MhAIC6GQghAIHLIggqipBRFSCqihBQUN0RQkqoguQy6uqdRgrYPpOLD9ppHrsu2jOLw8fjq7tG3wfQdIwcZDNF8uGVg6cJt32XvfnXzBmJzB/eHC27DgBRSmhwN24wd/5xrSc+W+1BJGJwDGvD8hcy7SecHYgrIL2bhIdndxlcb5923lQRJl5pa3FfN3GucOrd1oKus0WIids87GSQPV0oBpa0bIXEg2+UD3Z3RQzA0Yg6Akn3pZct5+5BMeEedeMOyuwxk8niexBaJ21xIDhsHFOIdt/wDnagBKb3JIdna0TrEdH9bEEmW5uS4G924YyOnK3P3oJElyLmTaMNmWcHDmtnkgmW4zfxuGxvkGkEZ32IK3cMxxm3kaCoq8czjZwMxc112kvjADgdoueZGn0DQ2kRUw4nAYrYJ4za1yOTkI9vIjPOJzDxuntDOp5SG3MT7uiPIN7DzjwXg1abJ+D9D4TX41PjHVgbCeVcsvZFVhEmVwvgUMCyCUAgEAghAIjQsthAFUQgLIithyIKujCqTDPIwIxMIpZeLmif8AImjd1BwXSk4tDjrxu07R8H13DnfdcFfSfl3gJtUajjHgRks4x+AtqAwYLnDltGVkVSPU2pv5zWW5HTPv6igu3Uqe+YpsN74XPeb57zg5kMmyakyOcSPc0bb3wN4xzRlb4Tb8vagudSH7pIWfUjeerMoZXbqW/wDftHRD/wAkMrt1LO+oHof+apkwamDfO7qYB7VDK41NZ++k6gzwVMrDU6LfLN2x/hQys3U+AG/GT32XxRj1NRMr/klT3uXSkjeXi/qRcmS6s07zeQyvdldz5XOcbbM9qhlH5LUnyHekePUUMrN1YowLCI2/xp/xIuVmat0gNxDY/wCLNf8A1JhctdFoyGEkxRhpcADm43Az3lEytpLR7Z4nRuy3sd8l+4rF6ReMO/h9adK8Wh4GopixzmPFnNNnBfNtExOJfpqXresWr0kotUbRhQRZBFkAURCAQQgEQ9RQihECAsqqcKGRZAqViMS59SMitQ52fXtGT8ZBDJ8uGN3a0L6VZzES/L6kYtMNK0wgoKlBF0EXQRiVBiQRiQGJBBcgjEgjEggu3qCyARUooUEtcNlxdFw4etOiuMZx0Y/ORjzgNr2eIXDX090bo6voeA8Vw7bLdJ/R4rEvC+9kXQRdEyLoZRdDIQF0AghBoQCKlECCQgLoC6CrkRiqmLUMWh9E1Lmx0MP0McZ+y4gd1l79Kc0h+d8XXGtZ3F1eVUoKlBUlBBKCjnKiMaCQUEqCCUFS4co7QgqZGja5o6XAKqU6thG2aEdM0Q9qzuju1st2K8rUw21NP6eLxU317rGlf3ZLdp6kG2pg6pWn1KcSvdrganuyW7WaiG2qi6sZ9QTiV7rwNT3XldJt0TJK+X3aWY3YixkRc0O3kExnac+tZm9O7rXT1YjGGKhboenlbLHW1Aex2JpDbdX6vYm+q8PV+H1eldwhaPHxrz0MHtITiwx7Pf4fV52srYJpHSU2IRONwHAAg77AE2F14tTG7k+74Wb8OIv1glYehF0AgLoC6AQRdBN0D7qAugLoIugLoC6CMSoMSIo8XCJJlBrPV0LTFFTsmjLi8FwcS0naMnDkXfT1MRh87xXhd9t2J/I88IOkTsooh9l/81dONPeHm9jj3bfoU7XvSh2UkI6h7XlONPdfYo9yfrCjtctLnZDC30Ptupxvi17F/Z+pTtaNMn4ULfs0/wCBON8V9in3I+qjtPaZPx0Q+4PUxTjfGWvYp9yPrJbtLaYP7WwdDnj1AKcX4y17FPu1/VQ1elTtrnDokn/Epxfmvsc/2/ReKfSYv+nnPaXR8ae15JCsa2O6T4LPXH0/yvxmkDt0g77MEQTjyf8Az69/0QRWHbpCo6gxvqU40tR4Cnf9IUdTVB26QrOqWynFlr2Knf8Ab+CZNGOcCH1lY8HaHTkg9IspxJajwlI9Z/T+CBoKP5c5/wA0qb5b9mr3n6p8hQ7+NPTK/wAU3yezU+P1lPkKn3tcemSTxTiWX2XT7frKw0HTfuh1ucfapvt3PZtL3VhoenHxLOy6b7d19n0vdhYaLgHxMX3Gqb7d2o0NP3YMbRxDZHGOhjfBTM92o06doOa0DYAOgWUbiMLIoQCCEAglBCAQPuoIugLqiLoC6CLoC6CLoC6IEBdVEXQF0EIBAImUIJugLoC6Augi6ARQgEE3UAgEEXRRdBN0VF0BdAIBAXQCIEH/2Q=="}
width={500}
height={500}
alt="image"
className='w-full h-[400px] object-cover'
/>
<h1 className="line-clamp-2 scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl absolute top-[45%] max-w-3xl bg-gradient-to-r from-blue-950 to-blue-500 left-[50%] -translate-x-1/2 text-white px-3 py-1 rounded-md">
Lenovo Thinkpad E14, Intel Core I5-1135g7, 8gb Ram, 256gb Ssd Black
</h1>
<p className='px-4 py-4'>The Lenovo ThinkPad E14 is a business-oriented laptop that combines solid performance with reliability. It features an Intel Core i5 processor, offering a good balance of speed and power efficiency for everyday tasks like office work, web browsing, and multimedia.</p>
<div className="flex py-4 px-4 w-full justify-between">
<div className="flex items-center justify-center gap-8">
<p><span className='text-blue-700'>Brand:</span>Hp</p>
<p><span className='text-blue-700'>Stock:</span>32items</p>
</div>
<div className='px-4 '>
<Button>
<Bookmark/>
Bookmark
</Button>
</div>
</div>
</div>
)
}
This is a sample about a detailed part of a product.
Main Section (Product Listing and Detailed Page) 2 Product Alone
import Image from 'next/image'
import Link from 'next/link'
import React from 'react'
export default function Product() {
return (
<Link href={"/"} className='flex items-center gap-3 hover:bg-blue-100 rounded-md px-4 py-2 transition-all hover:-translate-y-1 duration-500'>
<Image
src={"data:image/jpeg;base64,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"}
width={500}
height={500}
alt="image"
className='w-16 h-16 rounded-lg'
/>
<div>
<h2 className='text-blue-700'>HP Spectre X360 Laptop 14-ef2017nia 9t729ea - 1TB SSD - 8GBRAM</h2>
<div className="flex items-center justify-between">
<p><span>Brand:</span>Hp</p>
<p><span>Stock:</span>32items</p>
</div>
</div>
</Link>
)
}
This is how the product itself is going to look like.
Main Section (Product Listing and Detailed Page) 2 Product Listing
import React from 'react'
import Product from './Product'
export default function ProductList() {
return (
<div className='space-y-3'>
<Product/>
<Product/>
<Product/>
<Product/>
<Product/>
</div>
)
}
This is how the product Listing looks like.
Main Section (Product Listing and Detailed Page) 1
import React from 'react'
import Header from './Header'
import ProductList from './ProductList'
export default function StorePage() {
return (
<div className='min-h-screen bg-gradient-to-r from-blue-600 to-blue-950 py-8 px-8'>
<div className="rounded-lg bg-blue-100 min-h-screen">
<Header/>
<main className='grid grid-cols-12 bg-gray-50 min-h-screen'>
<div className='col-span-4 pt-3'>
<ProductList/>
</div>
<div className='col-span-8 bg-gray-100'>
Product detailed page
</div>
</main>
</div>
</div>
)
}
This is how the main section looks like.
Next Image Putting Outside links
<Image
src={"data:image/jpeg;base64,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"}
width={500}
height={500}
alt="image"
className='w-56 h-56'
/>
Here simply copy the image address not link address
Next Image (Outside Links) Configuration to Allow all Outside Links.
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: '**',
},
],
},
};
export default nextConfig;
Go to Next Config and paste this. And Next Image Note: it always goes with a src, alt , width and height.
Page Group -> This is done with pages which have the same layout.
Eg: (Group1) In brackets -> Services(Folder)-> page.tsx , Contact(Folder)-> page.tsx , Layout.tsx
Layout.tsx
import React from 'react'
export default function GroupOnelayout({children}:{children:any}) {
return (
<div>
<h1>This is Group 1 layout.</h1>
{children}
</div>
)
}
This is the detailed explanation of the Page Group.
Search params -> These ones want to look like the params but they are different. Location -> products(folder) -> [id] -> page.tsx
products
page.tsx
{/* Products */}
<a href="/product/1?page=5" className="text-blue-600">Product 1</a>
[id]
page.tsx
http://localhost:3000/product/2?page=5
import React from 'react'
export default async function page({
params,
searchParams,
}: {
params: Promise<{ slug: string, id:string }>
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}) {
const id = (await params).id
const page = (await searchParams).page
return (
<div>
<h2>This is a detailed Page.</h2>
Page - {id}
SearchParam - {page}
{/* http://localhost:3000/product/5 -> dynamic param */}
{/* http://localhost:3000/product/5?page=3 -> search param */}
</div>
)
}
This is a detailed Page.
Page - 2SearchParam - 5
This is the detailed explanation of a search param.
Dynamic page. [slug] or [id] or Detailed Page Location-> Products(folder) -> id(folder) -> page.tsx
import React from 'react'
export default async function page({
params,
}: {
params: Promise<{ slug: string , id:string}>
}) {
const id = (await params).id
return (
<div>
<h2>This is a detailed Page.</h2>
Page - {id}
</div>
)
}
We use id because this is the one we have used. remember [id] So now we can even parse it above and it will change dynamically. Eg http://localhost:3000/product/2 and it will change to Page - {2}
Error Page ( app(folder) -> error.tsx(file) )
import React from 'react'
export default function error() {
return (
<div>
You have got an error.
</div>
)
}
This is an error page and its purpose is to prevent a user from being scared that really something very bad has happened.
Not Found Page (http://localhost:3000/doesnot) A page that does not exist
import React from 'react'
export default function NotFound() {
return (
<div>
This page does not exist.
</div>
)
}
Location -> app(folder) -> not-found.ts(file)
Create 6 (Final Ui) Location -> Components(folder) -> LatestProjects.tsx(file)
'use client'
import React from 'react'
import Image from 'next/image'
import Link from 'next/link'
import { motion } from 'framer-motion'
interface Project {
title: string
description: string
image: string
link: string
}
const projects: Project[] = [
{
title: "Sefbuy",
description: "SEFBUY is an Ecommerce website designed to provide a seamless shopping experience for customers.",
image: "/project1.png?height=300&width=500",
link: "https://sefbuy.com/"
},
{
title: "Lamudi",
description: "Lamudi is a leading real estate platform connecting buyers and sellers across Uganda.",
image: "/project2.png?height=300&width=500",
link: "https://www.lamudi.co.ug/Lamudi/Index.aspx"
},
{
title: "Gaba Hope For Kids",
description: "This is a Charity Organization supporting unprivileged children with Education, Healthcare and Empowerment in Uganda.",
image: "/project3.png?height=300&width=500",
link: "https://www.gabahopeforkids.org/"
}
]
const BreathingBackground = () => (
<div className="absolute inset-0 z-0">
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="grid" width="50" height="50" patternUnits="userSpaceOnUse">
<path d="M 50 0 L 0 0 0 50" fill="none" stroke="rgba(255,255,255,0.5)" strokeWidth="1"/>
</pattern>
</defs>
<motion.rect
width="100%"
height="100%"
fill="url(#grid)"
animate={{
scale: [1, 1.05, 1],
opacity: [0.3, 0.5, 0.3],
}}
transition={{
duration: 5,
repeat: Infinity,
ease: "easeInOut"
}}
/>
</svg>
</div>
)
const AnimatedSection = motion.section
export default function LatestProjects({projectData}: {projectData: Project[]}) {
return (
<AnimatedSection className="relative overflow-hidden">
<BreathingBackground />
<div className="latest-container relative z-10">
<h2 className="text-4xl font-semibold text-center mb-4 text-gray-800 dark:text-white name-header">Latest Projects</h2>
<div className="latest-card-container">
{projectData.map((project, index) => (
<motion.div
key={index}
initial={{ opacity: 0, y: 50 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: index * 0.2 }}
className="bg-white dark:bg-gray-800 rounded-xl shadow-xl overflow-hidden transform hover:scale-105 transition duration-300"
>
<div className="relative h-64 w-full image-container">
<Image
src={project.image}
alt={project.title}
layout="fill"
objectFit="cover"
className="transition-transform duration-300 hover:scale-110 inner-image"
/>
</div>
<div className="p-6">
<h3 className="text-2xl font-semibold mb-3 text-gray-800 dark:text-white">{project.title}</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">{project.description}</p>
<Link href={project.link} className="inline-block bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded transition duration-300">
View Project
</Link>
</div>
</motion.div>
))}
</div>
<div className="w-[100%] h-[10vh] mt-3 flex items-center justify-center">
<button className='bg-blue-500 hover:bg-blue-600 text-white font-bold py-3 px-6 rounded-lg transition duration-300 text-sm'>
<Link href="/projects">
View All Projects
</Link>
</button>
</div>
</div>
</AnimatedSection>
)
}
This is the final Ui where the the created products are going to be shown.
Create 5 (Go on the Ui) Location -> Projects(folder) -> page.tsx(file)
import { fetchProject } from '@/actions/Project'
import LatestProjects from '@/components/LatestProjects'
import Link from 'next/link'
import React from 'react'
export default async function page() {
const dbProjects = await fetchProject() || []
return (
<div className='p-5 mt-[72px]'>
<div className='w-full p-3 flex'>
<Link href="/project/new" className='px-3 py-4 bg-blue-500 text-white rounded-[10px] mt-4 font-bold'>
Create New Project
</Link>
</div>
<LatestProjects projectData={dbProjects}/>
</div>
)
}
This is the ui front page which is going to be turned into a server side.
Create 4 (Getting things from the database) Location -> Location -> Overall outside all others -> actions(folder) -> Projects.ts(file)
export async function fetchProject(){
try {
const fetchedProject = await db.project.findMany({
orderBy:{
createdAt:"desc"
}
})
return fetchedProject
} catch (error) {
console.log(error)
}
}
This is the server actions functionality to acquire or get items from the data base. The items we just created.
Create 3 (Server actions) Location -> Overall outside all others -> actions(folder) -> Projects.ts(file)
"use server"
import { ProjectProps } from "@/components/Forms/CreateNewProjectForm";
import { db } from "@/prisma/db";
import { revalidatePath } from "next/cache";
export async function createNewProject(data:ProjectProps){
try {
const createdNewProject = await db.project.create({
data
})
revalidatePath("/project")
return createdNewProject
} catch (error) {
console.log(error)
}
}
This is the server actions which is going to aid our create functionality.
Create 2 (Form) Location -> Components(folder) -> Forms(folder) -> CreateNewProjectForm(file)
"use client";
import React, { useState } from "react";
import { useForm } from "react-hook-form";
import toast from "react-hot-toast";
import { useRouter } from "next/navigation";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
import { Button } from "@/components/ui/button"
import { Label } from "@/components/ui/label"
import { createNewProject } from "@/actions/Project";
import Image from "next/image";
import { UploadButton } from "@/utils/uploadthing";
export type ProjectProps = {
image :string;
title: string;
description: string;
link:string;
slug: string;
}
export default function CreateNewProjectForm() {
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm<ProjectProps>();
const [formError, setFormError] = useState("");
const [loading, setLoading] = useState(false);
const[imageUrl,setImageUrl] = useState("/emptyImage.png")
const router = useRouter();
async function saveData(data: ProjectProps) {
data.slug = data.title.toLowerCase().split(" ").join("-");
data.image = imageUrl;
try {
setLoading(true)
await createNewProject(data)
toast.success("Project created successfully.")
router.push("/project")
router.refresh()
reset()
} catch (error) {
toast.error("Failed to create the project.")
console.log(error)
} finally {
setLoading(false)
}
}
return (
<section className="p-5 mt-[72px]">
<Card className="w-full max-w-2xl mx-auto bg-gradient-to-br from-blue-500 to-blue-900 shadow-xl">
<CardHeader className="text-white">
<CardTitle className="text-2xl font-bold text-center mb-2">New Project</CardTitle>
</CardHeader>
<CardContent className="bg-white bg-opacity-90 rounded-b-lg">
<form className="space-y-6" onSubmit={handleSubmit(saveData)}>
<div className="space-y-2">
<Label htmlFor="title" className="text-gray-700">Project Title</Label>
<Input
type="text"
id="title"
{...register("title", { required: "Title is required" })}
placeholder="Enter project title"
className="bg-white"
/>
{errors.title && (
<p className="text-sm text-red-500">{errors.title.message}</p>
)}
</div>
<div className="space-y-2">
<Label htmlFor="description" className="text-gray-700">Description</Label>
<Textarea
id="description"
rows={4}
{...register("description", {
required: "Description is required",
})}
placeholder="Enter a brief description of the project"
className="bg-white"
/>
{errors.description && (
<p className="text-sm text-red-500">{errors.description.message}</p>
)}
</div>
{formError && <p className="text-sm text-red-500">{formError}</p>}
<div className="space-y-2">
<Label htmlFor="link" className="text-gray-700">Link for your Project</Label>
<Input
type="text"
id="link"
{...register("link", { required: "Link for your project is required" })}
placeholder="Enter your Project link"
className="bg-white"
/>
{errors.title && (
<p className="text-sm text-red-500">{errors.link?.message}</p>
)}
</div>
<div className="space-y-2 ">
<Label htmlFor="title" className="text-gray-700">Project Image</Label>
<div className="w-full min-h-[40vh] bg-slate-300 rounded-[10px]">
<div className="w-full h-[30vh] flex items-center justify-center ">
<Image
src={imageUrl}
width={512}
height={512}
alt="Image name"
className="max-h-[100%] max-w-[40%]"
/>
</div>
<div className="w-full min h-[15vh] flex items-center justify-center ">
<UploadButton
endpoint="imageUploader"
onClientUploadComplete={(res) => {
// Do something with the response
console.log("Files: ", res);
setImageUrl(res[0].url)
// alert("Upload Completed");
}}
onUploadError={(error: Error) => {
// Do something with the error.
alert(`ERROR! ${error.message}`);
}}
/>
</div>
</div>
</div>
<Button
type="submit"
disabled={loading}
className="w-full bg-blue-600 hover:bg-blue-700 text-white"
>
{loading ? "Creating New Project..." : "Create New Project"}
</Button>
</form>
</CardContent>
</Card>
</section>
);
}
This is the form with an input for an image comprehensively.
Create 1 (Form Page) Location ->Projects(folder) ->New(folder) ->page.tsx(file)
import CreateNewProjectForm from '@/components/Forms/CreateNewProjectForm'
import React from 'react'
export default function page() {
return (
<div>
<CreateNewProjectForm/>
</div>
)
}
This is the Page where the create Form is going to placed.
Git Commands
Download Git -> Which gives us Gitbash, Git Graphical User Interface(GUI), Git Command Line Interface(CMD)
Commands
1. ls -> list all the items in the current directory.
2. clear -> wipes clean the entire gitbash terminal.
3. ls -l -> Gives you a fully detailed analysis of all the folders in the
current directory.
4. ls -a -> Shows any possible hidden files in the current directory.
5. mkdir -> Create a new directory eg mkdir songs, creates new folder
called songs.
6. rm -r -> Delete a directory or a folder eg rm -r songs
7. rm -rf -> Forceful delete of a directory or a folder eg rm -rf songs
8. cd -> Change the directory eg cd movies/ , change and enter the
directory or folder.
9. code . -> Open Vscode
10. touch -> Create a new file eg touch index.html
11. cat -> Gives a detailed analysis of the contents inside a file eg
cat index.html
12. rm -> delete a file eg rm index.html
13. rm -f -> forceful delete a file eg rm -f index.html
14. mv -> Renames files or folders eg mv index.html services.html, renames
index.html to services.html
15. pwd -> print current directory
16. cd.. -> Go backwards
These are the comprehensive git commands.
Prisma the Ui where the fetched items are being shown from the database. (2)
"use client"
import React, { useState } from "react";
import Link from "next/link";
import { CodeSnippet } from "@prisma/client";
import CodeSnippetCard from "./CodeSnippet";
export default function CodeLibrary({codeData}: {codeData: CodeSnippet[]}) {
const [search, setSearch] = useState("");
const handleCopy = (code: string) => {
navigator.clipboard.writeText(code);
};
const filteredSnippets = codeData.filter((snippet) =>
snippet.title.toLowerCase().includes(search.toLowerCase())
);
return (
<div className="min-h-screen bg-blue-950 flex flex-col items-center w-full rounded-[5px]">
<h1 className="lg:text-3xl md:text-2xl sm:text-2xl text-2xl font-bold text-white mb-6 mt-6">My Code Library</h1>
{/* search bar */}
<div className="w-full p-[0.5rem] flex items-center justify-center">
<input
type="text"
placeholder="Search Code Snippets..."
value={search}
onChange={(e) => setSearch(e.target.value)}
className=" px-4 py-2 rounded-[20px] w-full max-w-3xl bg-white text-blue-950 font-bold placeholder-gray-500 focus:outline-none focus:ring focus:ring-blue-500"
/>
</div>
<div className="w-full p-[0.5rem] flex items-center justify-start">
<Link href="/new" className="bg-blue-900 mb-2 text-white border-white rounded-[10px] border-b-[1px] border-l-[1px] p-2">
<button>
<p>Create New Snippet</p>
</button>
</Link>
</div>
<div className="code-snippet-container">
{filteredSnippets.map((snippet, index) => (
<CodeSnippetCard
key={index}
title={snippet.title}
code={snippet.code}
description={snippet.description}
onCopy={() => handleCopy(snippet.code)}
/>
))}
{filteredSnippets.length === 0 && (
<p className="text-gray-500 text-center">No snippets found.</p>
)}
</div>
</div>
);
}
{codeData}: {codeData: CodeSnippet[] -> Remember that the CodeSnippet[] is from the model, the one called CodeSnippet. location components
Prisma the Ui where the fetched items are being shown from the database. (1)
import CodeLibrary from '@/components/CodeLibrary'
import { fetchCode } from '../../actions/CodeSnippet'
export default async function Docs() {
const code = await fetchCode() || []
// console.log(code)
return (
<CodeLibrary codeData={code}/>
)
}
Watch out, the data we are bringing is a server side data which means that by all means the top surface will have to turn into a server side related with the async and await. There fore it shouldn't bear the client bases, the use client. We call our ui as a component instead and then simply pass in the data as props. Location -> docs(folder) -> page.tsx(file)
Prisma Getting or Aquiring things from the database onto the Ui
import { db } from "@/prisma/db";
export async function fetchCode(){
try {
const fetchedCode = await db.codeSnippet.findMany({
orderBy:{
createdAt:"desc"
}
})
return fetchedCode
} catch (error) {
console.log(error)
}
}
This is the get functionality to acquire all things from a database onto the Ui. Note: db -> this one comes from the db.ts inside the prisma folder, codeSnippet -> this one comes from the name given to the model called CodeSnippet but however here it starts with a small letter, we use a property called findMany. Location -> actions(folder) ->CodeSnippet.ts(file)
Prisma Create Functionality in actions
import { CodeSnippetProps } from "@/components/CreateNewCodeSnippetForm";
import { db } from "@/prisma/db";
import { revalidatePath } from "next/cache";
export async function createCode(data:CodeSnippetProps){
// console.log(data)
//We create the data to be shown in the database.
try {
const createdCode = await db.codeSnippet.create({
data
})
// console.log(createdCode)
//Then we return to be able to use this data anywhere else eg to fetch the data on the ui.
revalidatePath("/docs")
return createdCode
} catch (error) {
console.log(error)
}
}
This is a create functionality. Location -> Inside actions(folder) -> CodeSnippet.ts
Prisma Create Form
"use client";
import React, { useState } from "react";
import { useForm } from "react-hook-form";
import toast from "react-hot-toast";
import { useRouter } from "next/navigation";
import { createCode } from "@/actions/CodeSnippet";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
import { Button } from "@/components/ui/button"
import { Label } from "@/components/ui/label"
export type CodeSnippetProps = {
title: string;
code: string;
description: string;
slug: string;
};
export default function CreateNewCodeSnippetForm() {
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm<CodeSnippetProps>();
const [formError, setFormError] = useState("");
const [loading, setLoading] = useState(false);
const router = useRouter();
async function saveData(data: CodeSnippetProps) {
data.slug = data.title.toLowerCase().split(" ").join("-");
try {
setLoading(true)
await createCode(data)
toast.success("Codesnippet created successfully.")
router.push("/docs")
router.refresh()
reset()
} catch (error) {
toast.error("Failed to create the code snippet.")
console.log(error)
} finally {
setLoading(false)
}
}
return (
<Card className="w-full max-w-2xl mx-auto bg-gradient-to-br from-blue-500 to-blue-900 shadow-xl">
<CardHeader className="text-white">
<CardTitle className="text-2xl font-bold text-center mb-2">Create New Code Snippet</CardTitle>
</CardHeader>
<CardContent className="bg-white bg-opacity-90 rounded-b-lg">
<form className="space-y-6" onSubmit={handleSubmit(saveData)}>
<div className="space-y-2">
<Label htmlFor="title" className="text-gray-700">Snippet Title</Label>
<Input
type="text"
id="title"
{...register("title", { required: "Title is required" })}
placeholder="Enter snippet title"
className="bg-white"
/>
{errors.title && (
<p className="text-sm text-red-500">{errors.title.message}</p>
)}
</div>
<div className="space-y-2">
<Label htmlFor="code" className="text-gray-700">Code</Label>
<Textarea
id="code"
rows={6}
{...register("code", { required: "Code is required" })}
placeholder="Enter your code here"
className="font-mono bg-white"
/>
{errors.code && <p className="text-sm text-red-500">{errors.code.message}</p>}
</div>
<div className="space-y-2">
<Label htmlFor="description" className="text-gray-700">Description</Label>
<Textarea
id="description"
rows={4}
{...register("description", {
required: "Description is required",
})}
placeholder="Enter a brief description of the code snippet"
className="bg-white"
/>
{errors.description && (
<p className="text-sm text-red-500">{errors.description.message}</p>
)}
</div>
{formError && <p className="text-sm text-red-500">{formError}</p>}
<Button
type="submit"
disabled={loading}
className="w-full bg-blue-600 hover:bg-blue-700 text-white"
>
{loading ? "Creating Snippet..." : "Create Code Snippet"}
</Button>
</form>
</CardContent>
</Card>
);
}
This a default form for creating a new item. Location -> Components
Prisma additions to package.json
"scripts": {
"postinstall": "prisma generate",
"preview": "next build && next start"
}
"postinstall": "prisma generate", -> run or install prisma generate onto the hosted version. "preview": "next build && next start" -> Overall error checker to check our code thoroughly before deployment to solve any impending errors. run on terminal -> pnpm run preview
Prisma schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mongodb"
url = env("DATABASE_URL")
}
model CodeSnippet {
id String @id @default(auto()) @map("_id") @db.ObjectId
title String
code String
description String
slug String @unique
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
file name(schema.prisma) location(Inside prisma(folder) -> prisma.schema(file))
Prisma Instance
import { PrismaClient } from "@prisma/client";
declare global {
var prisma: PrismaClient | undefined;
}
export const db = globalThis.prisma || new PrismaClient();
if (process.env.NODE_ENV !== "production") globalThis.prisma = db;
file name(db.ts) location(Inside prisma(folder) -> db.ts(file))
.env
DATABASE_URL="mongodb+srv://clancyro1789:VD62uLe4VVYZeTsr@cluster0.7rqx7.mongodb.net/(any new db name)"
enviromental variables / env
Generate Random Numbers in JavaScript
function getRandomNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
console.log(getRandomNumber(1, 100)); // Example: Generates a random number between 1 and 100
A simple JavaScript function to generate random numbers within a specified range using Math.random().