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

Edit

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.

Edit

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.

Edit

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.

Edit

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.

Edit

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.

Edit

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.

Edit

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,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"}
                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.

Edit

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.

Edit

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.

Edit

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.

Edit

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

Edit

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.

Edit

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.

Edit

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.

Edit

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}

Edit

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.

Edit

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)

Edit

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.

Edit

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.

Edit

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.

Edit

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.

Edit

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.

Edit

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.

Edit

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.

Edit

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

Edit

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)

Edit

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)

Edit

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

Edit

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

Edit

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

Edit

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))

Edit

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))

Edit

.env

 DATABASE_URL="mongodb+srv://clancyro1789:VD62uLe4VVYZeTsr@cluster0.7rqx7.mongodb.net/(any new db name)"

enviromental variables / env

Edit

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().