├── public ├── robots.txt ├── showcase.jpg ├── vercel.svg ├── next.svg └── Illustration.svg ├── app ├── favicon.ico ├── lib │ ├── utils.ts │ └── HighLight.tsx ├── providers │ └── ThemeProvider.tsx ├── page.tsx ├── api │ ├── helper │ │ ├── parseQuery.ts │ │ ├── createPayload.ts │ │ ├── parseRequestBody.ts │ │ ├── schema.ts │ │ ├── filterUsers.ts │ │ └── filterProducts.ts │ ├── data │ │ ├── product │ │ │ └── types.ts │ │ └── user │ │ │ ├── types.ts │ │ │ └── users.ts │ ├── products │ │ ├── category │ │ │ └── route.ts │ │ ├── route.ts │ │ └── [id] │ │ │ └── route.ts │ └── users │ │ ├── route.ts │ │ └── [id] │ │ └── route.ts ├── docs │ ├── page.tsx │ ├── Content.tsx │ ├── users │ │ ├── User.tsx │ │ ├── AddUser.tsx │ │ ├── DeleteUser.tsx │ │ ├── SingleUser.tsx │ │ ├── UpdateUser.tsx │ │ ├── LimitedUser.tsx │ │ ├── PaginationUser.tsx │ │ ├── AllUser.tsx │ │ └── snippets.tsx │ ├── products │ │ ├── AddProduct.tsx │ │ ├── DeleteProduct.tsx │ │ ├── PaginationProduct.tsx │ │ ├── UpdateProduct.tsx │ │ ├── SingleProduct.tsx │ │ ├── LimitedProduct.tsx │ │ ├── ProductCategory.tsx │ │ ├── products.tsx │ │ ├── ProductofCategory.tsx │ │ ├── AllProducts.tsx │ │ └── snippets.tsx │ └── Sidebar.tsx ├── sitemap.xml ├── context │ └── HighlightContext.tsx ├── components │ ├── ToggleTheme.tsx │ ├── CopyButton.tsx │ ├── Resources.tsx │ ├── About.tsx │ ├── Hero.tsx │ ├── ui │ │ ├── scroll-area.tsx │ │ └── button.tsx │ ├── Navbar.tsx │ └── Route.tsx ├── hooks │ └── useCopyToClipboard.tsx ├── layout.tsx └── globals.css ├── .eslintrc.json ├── postcss.config.js ├── next.config.mjs ├── components.json ├── .gitignore ├── tsconfig.json ├── package.json ├── README.md └── tailwind.config.ts /public/robots.txt: -------------------------------------------------------------------------------- 1 | # Allow all crawlers 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vishal-gg/FakeStoreApi/HEAD/app/favicon.ico -------------------------------------------------------------------------------- /public/showcase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vishal-gg/FakeStoreApi/HEAD/public/showcase.jpg -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals", 3 | "rules": { "react/no-unescaped-entities": 0 } 4 | } -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /app/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /app/providers/ThemeProvider.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { ThemeProvider as NextThemeProvider } from "next-themes"; 4 | import { type ThemeProviderProps } from "next-themes/dist/types"; 5 | 6 | const ThemeProvider = ({ children, ...props }: ThemeProviderProps) => { 7 | return {children} 8 | } 9 | 10 | export default ThemeProvider; -------------------------------------------------------------------------------- /app/page.tsx: -------------------------------------------------------------------------------- 1 | import About from "./components/About" 2 | import Hero from "./components/Hero" 3 | import Resources from "./components/Resources" 4 | import Route from "./components/Route" 5 | 6 | const page = () => { 7 | return ( 8 |
9 | 10 | 11 | 12 | 13 |
14 | ) 15 | } 16 | 17 | export default page 18 | -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | headers: async () => { 4 | return [ 5 | { 6 | source: "/api/:path*", 7 | headers: [ 8 | { 9 | key: "Access-Control-Allow-Origin", 10 | value: "*", 11 | }, 12 | ], 13 | }, 14 | ]; 15 | }, 16 | }; 17 | 18 | export default nextConfig; 19 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "app/globals.css", 9 | "baseColor": "slate", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils" 16 | } 17 | } -------------------------------------------------------------------------------- /app/api/helper/parseQuery.ts: -------------------------------------------------------------------------------- 1 | 2 | type queryType = { 3 | page_str: string | null; 4 | limit_str: string | null; 5 | } 6 | 7 | export const parseQuery = (query : queryType) => { 8 | const page_str = query.page_str 9 | const limit_str = query.limit_str 10 | 11 | const page = page_str ? parseInt(page_str, 10) : 1; 12 | const limit = limit_str ? parseInt(limit_str, 10) : 50; 13 | 14 | return {page, limit} 15 | } -------------------------------------------------------------------------------- /app/docs/page.tsx: -------------------------------------------------------------------------------- 1 | import Sidebar from "./Sidebar"; 2 | import Content from "./Content"; 3 | 4 | const page = () => { 5 | return ( 6 |
7 | 10 |
11 | 12 |
13 |
14 | ) 15 | } 16 | 17 | export default page; 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/lib/HighLight.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useEffect } from 'react'; 4 | import hljs from 'highlight.js/lib/core'; 5 | import javascript from 'highlight.js/lib/languages/javascript'; 6 | hljs.registerLanguage('javascript', javascript) 7 | import 'highlight.js/styles/github-dark.css'; 8 | import { useTiggerHightlight } from '@/context/HighlightContext'; 9 | 10 | export default function HighLight() { 11 | const { triggerHighlight } = useTiggerHightlight(); 12 | 13 | useEffect(() => { 14 | hljs.highlightAll() 15 | console.clear() 16 | }, [triggerHighlight]); 17 | 18 | return
; 19 | } -------------------------------------------------------------------------------- /app/api/helper/createPayload.ts: -------------------------------------------------------------------------------- 1 | import { productsType, productsTypePartial } from "@product/types" 2 | import { UserType , UserTypePartial } from "@user/types" 3 | 4 | type payloadType = { 5 | status: "SUCCESS" | "ERROR" | "UNAUTHORIZED" | "FORBIDDEN" | "NOT-FOUND" | "BAD-REQUEST"; 6 | message: string; 7 | products?: productsType[]; 8 | product?: productsTypePartial; 9 | categories?: any; 10 | users?: UserType[]; 11 | user?: UserTypePartial; 12 | } 13 | 14 | export const createPayload = ({status, message, product, products, categories, user, users} : payloadType) => { 15 | return {status, message, product, products, categories, user, users} 16 | } -------------------------------------------------------------------------------- /app/api/helper/parseRequestBody.ts: -------------------------------------------------------------------------------- 1 | import type { NextRequest } from "next/server"; 2 | 3 | export const parseRequestBody = async (request: NextRequest): Promise => { 4 | let requestBody; 5 | if (request.headers.get("Content-Type")?.startsWith("application/json")) { 6 | requestBody = await request.json() 7 | } else { 8 | const formData = await request.formData() 9 | requestBody = Object.fromEntries(formData) 10 | } 11 | if (!requestBody || Object.keys(requestBody).length === 0) { 12 | throw new Error( 13 | `Sorry, it appears you've sent ${request.method} request without any data.` 14 | ) 15 | } 16 | return requestBody as T; 17 | } -------------------------------------------------------------------------------- /app/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | https://fakestoreapi.in/ 12 | 2024-03-31T18:46:01+00:00 13 | 1.00 14 | 15 | 16 | https://fakestoreapi.in/docs 17 | 2024-03-31T18:46:01+00:00 18 | 0.80 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/api/data/product/types.ts: -------------------------------------------------------------------------------- 1 | export type productsType = { 2 | id: number 3 | title: string; 4 | price: number; 5 | category: string; 6 | image: string; 7 | description: string; 8 | brand: string; 9 | model: string; 10 | color?: string; 11 | discount?: number; 12 | onSale?: boolean; 13 | popular?: boolean; 14 | } 15 | 16 | export type productsTypePartial = Partial<{ 17 | id: number | string; 18 | title: string; 19 | price: number | string; 20 | category: string; 21 | image: string; 22 | description: string; 23 | brand: string; 24 | model: string; 25 | color?: string; 26 | discount?: number | string; 27 | onSale?: boolean; 28 | popular?: boolean; 29 | }> 30 | -------------------------------------------------------------------------------- /app/context/HighlightContext.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { Dispatch, SetStateAction, createContext, useContext, useState } from "react" 4 | 5 | type Type = { 6 | triggerHighlight: boolean; 7 | setTriggerHighlight: Dispatch> 8 | } 9 | const TriggerContext = createContext(undefined) 10 | 11 | export const HighlightContext = ({children} : {children: React.ReactNode}) => { 12 | const [triggerHighlight, setTriggerHighlight] = useState(false) 13 | 14 | return ( 15 | 16 | {children} 17 | 18 | ) 19 | } 20 | 21 | export const useTiggerHightlight = () => { 22 | const trigger = useContext(TriggerContext) 23 | if (trigger === undefined) { 24 | throw new Error("useContext must be used within provider") 25 | } 26 | return trigger; 27 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "incremental": true, 15 | "baseUrl": "./app", 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./*"], 23 | "@components/*": ["components/*"], 24 | "@product/*": ["api/data/product/*"], 25 | "@user/*": ["api/data/user/*"], 26 | "@data/*": ["api/data/*"], 27 | "@helper/*": ["api/helper/*"], 28 | } 29 | }, 30 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 31 | "exclude": ["node_modules"] 32 | } 33 | -------------------------------------------------------------------------------- /app/docs/Content.tsx: -------------------------------------------------------------------------------- 1 | import { Products } from "./products/products"; 2 | import HightLight from "@/lib/HighLight"; 3 | import { HighlightContext } from "@/context/HighlightContext"; 4 | import User from "./users/User"; 5 | 6 | const Content = () => { 7 | return ( 8 | 9 |
10 |
11 |

Getting Started

12 |

13 | Alright, so this documentation basically shows you how to use our API like a pro.
14 | {/* We've got all sorts of goodies in there: products, users, and more!
15 | It's your ultimate guide to making our API work for you.
*/} 16 |

17 |
18 | 19 | 20 | 21 |
22 |
23 | ) 24 | } 25 | 26 | export default Content; 27 | -------------------------------------------------------------------------------- /app/docs/users/User.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { TbUsers } from "react-icons/tb"; 3 | import AllUser from "./AllUser"; 4 | import SingleUser from "./SingleUser"; 5 | import LimitedUser from "./LimitedUser"; 6 | import PaginationUser from "./PaginationUser"; 7 | import AddUser from "./AddUser"; 8 | import UpdateUser from "./UpdateUser"; 9 | import DeleteUser from "./DeleteUser"; 10 | 11 | const User = () => { 12 | return ( 13 | <> 14 |
15 |

16 | Users 17 |

18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 |
28 | 29 | ); 30 | }; 31 | 32 | export default User; 33 | -------------------------------------------------------------------------------- /app/docs/users/AddUser.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Button } from "@/components/ui/button"; 4 | import { AddUserOutputSnip, AddUserSnip } from "./snippets"; 5 | import { useState } from "react"; 6 | import { useTiggerHightlight } from "@/context/HighlightContext"; 7 | 8 | const AddUser = () => { 9 | const [showOutput, setShowOutput] = useState(false); 10 | const { setTriggerHighlight } = useTiggerHightlight(); 11 | return ( 12 |
13 |
14 |

Add a user

15 | 16 |
17 | 27 | {showOutput && } 28 |
29 | ); 30 | }; 31 | 32 | export default AddUser; 33 | -------------------------------------------------------------------------------- /app/docs/products/AddProduct.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Button } from "@/components/ui/button"; 4 | import { AddProductOutputSnip, AddProductSnip } from "./snippets"; 5 | import { useState } from "react"; 6 | import { useTiggerHightlight } from "@/context/HighlightContext"; 7 | 8 | const AddProduct = () => { 9 | const [showOutput, setShowOutput] = useState(false); 10 | const { setTriggerHighlight } = useTiggerHightlight(); 11 | return ( 12 |
13 |
14 |

Add a product

15 | 16 |
17 | 27 | {showOutput && } 28 |
29 | ); 30 | }; 31 | 32 | export default AddProduct; 33 | -------------------------------------------------------------------------------- /app/docs/users/DeleteUser.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Button } from "@/components/ui/button"; 4 | import { DeleteUserOutputSnip, DeleteUserSnip } from "./snippets"; 5 | import { useState } from "react"; 6 | import { useTiggerHightlight } from "@/context/HighlightContext"; 7 | 8 | const DeleteUser = () => { 9 | const [showOutput, setShowOutput] = useState(false); 10 | const { setTriggerHighlight } = useTiggerHightlight(); 11 | return ( 12 |
13 |
14 |

Delete a user

15 | 16 |
17 | 27 | {showOutput && } 28 |
29 | ); 30 | }; 31 | 32 | export default DeleteUser; 33 | -------------------------------------------------------------------------------- /app/docs/users/SingleUser.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Button } from "@/components/ui/button"; 4 | import { SingleUserOutputSnip, SingleUserSnip } from "./snippets"; 5 | import { useState } from "react"; 6 | import { useTiggerHightlight } from "@/context/HighlightContext"; 7 | 8 | const SingleUser = () => { 9 | const [showOutput, setShowOutput] = useState(false); 10 | const { setTriggerHighlight } = useTiggerHightlight(); 11 | return ( 12 |
13 |
14 |

Get single user

15 | 16 |
17 | 27 | {showOutput && } 28 |
29 | ); 30 | }; 31 | 32 | export default SingleUser; 33 | -------------------------------------------------------------------------------- /app/docs/users/UpdateUser.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Button } from "@/components/ui/button"; 4 | import { UpdateUserOutputSnip, UpdateUserSnip } from "./snippets"; 5 | import { useState } from "react"; 6 | import { useTiggerHightlight } from "@/context/HighlightContext"; 7 | 8 | const UpdateUser = () => { 9 | const [showOutput, setShowOutput] = useState(false); 10 | const { setTriggerHighlight } = useTiggerHightlight(); 11 | return ( 12 |
13 |
14 |

Update a user

15 | 16 |
17 | 27 | {showOutput && } 28 |
29 | ); 30 | }; 31 | 32 | export default UpdateUser; 33 | -------------------------------------------------------------------------------- /app/docs/users/LimitedUser.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Button } from "@/components/ui/button"; 4 | import { LimitedUserOutputSnip, LimitedUserSnip } from "./snippets"; 5 | import { useState } from "react"; 6 | import { useTiggerHightlight } from "@/context/HighlightContext"; 7 | 8 | const LimitedUser = () => { 9 | const [showOutput, setShowOutput] = useState(false); 10 | const { setTriggerHighlight } = useTiggerHightlight(); 11 | return ( 12 |
13 |
14 |

Get limited users

15 | 16 |
17 | 27 | {showOutput && } 28 |
29 | ); 30 | }; 31 | 32 | export default LimitedUser; 33 | -------------------------------------------------------------------------------- /app/docs/users/PaginationUser.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Button } from "@/components/ui/button"; 4 | import { PaginationOutputSnip, PaginationSnip } from "./snippets"; 5 | import { useState } from "react"; 6 | import { useTiggerHightlight } from "@/context/HighlightContext"; 7 | 8 | const PaginationUser = () => { 9 | const [showOutput, setShowOutput] = useState(false); 10 | const { setTriggerHighlight } = useTiggerHightlight(); 11 | return ( 12 |
13 |
14 |

Pagination

15 | 16 |
17 | 27 | {showOutput && } 28 |
29 | ); 30 | }; 31 | 32 | export default PaginationUser; 33 | -------------------------------------------------------------------------------- /app/api/data/user/types.ts: -------------------------------------------------------------------------------- 1 | export interface UserType { 2 | id: number; 3 | email: string; 4 | username: string; 5 | password: string; 6 | name: { 7 | firstname: string; 8 | lastname: string; 9 | }; 10 | address: { 11 | city: string; 12 | street: string; 13 | number: string; 14 | zipcode: string; 15 | geolocation: { 16 | lat: number; 17 | long: number; 18 | }; 19 | }; 20 | phone: string; 21 | } 22 | 23 | export type UserTypePartial = Partial<{ 24 | id: number | string; 25 | email: string; 26 | username: string; 27 | password: string; 28 | name: Partial<{ 29 | firstname: string; 30 | lastname: string; 31 | }> 32 | address: Partial<{ 33 | city: string; 34 | street: string; 35 | number: string | number; 36 | zipcode: string; 37 | geolocation: Partial<{ 38 | lat: number | string; 39 | long: number | string; 40 | }> 41 | }> 42 | phone: string | number; 43 | }> -------------------------------------------------------------------------------- /app/docs/products/DeleteProduct.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Button } from "@/components/ui/button"; 4 | import { DeleteProductOutputSnip, DeleteProductSnip } from "./snippets"; 5 | import { useState } from "react"; 6 | import { useTiggerHightlight } from "@/context/HighlightContext"; 7 | 8 | const DeleteProduct = () => { 9 | const [showOutput, setShowOutput] = useState(false); 10 | const { setTriggerHighlight } = useTiggerHightlight(); 11 | return ( 12 |
13 |
14 |

Delete a product

15 | 16 |
17 | 27 | {showOutput && } 28 |
29 | ); 30 | }; 31 | 32 | export default DeleteProduct; 33 | -------------------------------------------------------------------------------- /app/docs/products/PaginationProduct.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Button } from "@/components/ui/button"; 4 | import { PaginationOutputSnip, PaginationSnip } from "./snippets"; 5 | import { useState } from "react"; 6 | import { useTiggerHightlight } from "@/context/HighlightContext"; 7 | 8 | const PaginationProduct = () => { 9 | const [showOutput, setShowOutput] = useState(false); 10 | const { setTriggerHighlight } = useTiggerHightlight(); 11 | return ( 12 |
13 |
14 |

Pagination

15 | 16 |
17 | 27 | {showOutput && } 28 |
29 | ); 30 | }; 31 | 32 | export default PaginationProduct; 33 | -------------------------------------------------------------------------------- /app/docs/products/UpdateProduct.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Button } from "@/components/ui/button"; 4 | import { UpdateProductOutputSnip, UpdateProductSnip } from "./snippets"; 5 | import { useState } from "react"; 6 | import { useTiggerHightlight } from "@/context/HighlightContext"; 7 | 8 | const UpdateProduct = () => { 9 | const [showOutput, setShowOutput] = useState(false); 10 | const { setTriggerHighlight } = useTiggerHightlight(); 11 | return ( 12 |
13 |
14 |

Update a product

15 | 16 |
17 | 27 | {showOutput && } 28 |
29 | ); 30 | }; 31 | 32 | export default UpdateProduct; 33 | -------------------------------------------------------------------------------- /app/docs/products/SingleProduct.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Button } from "@/components/ui/button"; 4 | import { SingleProductOutputSnip, SingleProductSnip } from "./snippets"; 5 | import { useState } from "react"; 6 | import { useTiggerHightlight } from "@/context/HighlightContext"; 7 | 8 | const SingleProduct = () => { 9 | const [showOutput, setShowOutput] = useState(false); 10 | const { setTriggerHighlight } = useTiggerHightlight(); 11 | return ( 12 |
13 |
14 |

Get single product

15 | 16 |
17 | 27 | {showOutput && } 28 |
29 | ); 30 | }; 31 | 32 | export default SingleProduct; 33 | -------------------------------------------------------------------------------- /app/docs/products/LimitedProduct.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Button } from "@/components/ui/button"; 4 | import { LimitedProductOutputSnip, LimitedProductSnip } from "./snippets"; 5 | import { useState } from "react"; 6 | import { useTiggerHightlight } from "@/context/HighlightContext"; 7 | 8 | const LimitedProduct = () => { 9 | const [showOutput, setShowOutput] = useState(false); 10 | const { setTriggerHighlight } = useTiggerHightlight(); 11 | return ( 12 |
13 |
14 |

Get limited products

15 | 16 |
17 | 27 | {showOutput && } 28 |
29 | ); 30 | }; 31 | 32 | export default LimitedProduct; 33 | -------------------------------------------------------------------------------- /app/docs/products/ProductCategory.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Button } from "@/components/ui/button"; 4 | import { ProductsCategoryOutputSnip, ProductsCategorySnip } from "./snippets"; 5 | import { useState } from "react"; 6 | import { useTiggerHightlight } from "@/context/HighlightContext"; 7 | 8 | const ProductCategory = () => { 9 | const [showOutput, setShowOutput] = useState(false); 10 | const { setTriggerHighlight } = useTiggerHightlight(); 11 | return ( 12 |
13 |
14 |

Get all categories

15 | 16 |
17 | 27 | {showOutput && } 28 |
29 | ); 30 | }; 31 | 32 | export default ProductCategory; 33 | -------------------------------------------------------------------------------- /app/docs/products/products.tsx: -------------------------------------------------------------------------------- 1 | import { GoPackage } from "react-icons/go"; 2 | import AllProducts from "./AllProducts"; 3 | import SingleProduct from "./SingleProduct"; 4 | import LimitedProduct from "./LimitedProduct"; 5 | import PaginationProduct from "./PaginationProduct"; 6 | import ProductCategory from "./ProductCategory"; 7 | import ProductofCategory from "./ProductofCategory"; 8 | import AddProduct from "./AddProduct"; 9 | import UpdateProduct from "./UpdateProduct"; 10 | import DeleteProduct from "./DeleteProduct"; 11 | 12 | export const Products = () => { 13 | return ( 14 |
15 |

16 | Products 17 |

18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /app/docs/products/ProductofCategory.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Button } from "@/components/ui/button"; 4 | import { 5 | ProductsofCategoryOutputSnip, 6 | ProductsofCategorySnip, 7 | } from "./snippets"; 8 | import { useState } from "react"; 9 | import { useTiggerHightlight } from "@/context/HighlightContext"; 10 | 11 | const ProductofCategory = () => { 12 | const [showOutput, setShowOutput] = useState(false); 13 | const { setTriggerHighlight } = useTiggerHightlight(); 14 | return ( 15 |
16 |
17 |

Get products of category

18 | 19 |
20 | 30 | {showOutput && } 31 |
32 | ); 33 | }; 34 | 35 | export default ProductofCategory; 36 | -------------------------------------------------------------------------------- /app/api/helper/schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | 3 | export const productSchema = z.object({ 4 | title: z.string().optional(), 5 | image: z.string().optional(), 6 | price: z.string().optional(), 7 | description: z.string().optional(), 8 | brand: z.string().optional(), 9 | model: z.string().optional(), 10 | color: z.string().optional(), 11 | category: z.string().optional(), 12 | discount: z.string().optional() 13 | }) 14 | 15 | export const userSchema = z.object({ 16 | email: z.string().email().optional(), 17 | username: z.string().optional(), 18 | password: z.string().optional(), 19 | name: z.object({ 20 | firstname: z.string().optional(), 21 | lastname: z.string().optional() 22 | }).optional(), 23 | address: z.object({ 24 | city: z.string().optional(), 25 | street: z.string().optional(), 26 | number: z.string().optional(), 27 | zipcode: z.string().optional(), 28 | geolocation: z.object({ 29 | lat: z.number().optional(), 30 | long: z.number().optional() 31 | }).optional() 32 | }).optional(), 33 | phone: z.string().optional() 34 | }); -------------------------------------------------------------------------------- /app/components/ToggleTheme.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useTheme } from "next-themes"; 4 | import { MdOutlineLightMode, MdOutlineDarkMode } from "react-icons/md"; 5 | import { useEffect, useState } from "react"; 6 | import { LuLoader } from "react-icons/lu"; 7 | 8 | const ToggleTheme = () => { 9 | const { theme, setTheme } = useTheme(); 10 | const [isClient, setIsClient] = useState(false) 11 | 12 | const handleToggle = () => { 13 | setTheme(theme === "light" ? "dark" : "light") 14 | } 15 | 16 | useEffect(() => { 17 | setIsClient(true) 18 | }) 19 | 20 | if (!isClient) return ( 21 |
22 | 23 |
24 | ) 25 | 26 | return ( 27 | 38 | ) 39 | } 40 | 41 | export default ToggleTheme; 42 | -------------------------------------------------------------------------------- /app/components/CopyButton.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from '@components/ui/button' 2 | import { IoCopyOutline } from "react-icons/io5"; 3 | import { FaCheck } from "react-icons/fa6"; 4 | import {motion, AnimatePresence} from 'framer-motion' 5 | 6 | type propsType = { 7 | handleCopy: () => void; 8 | isCopied: boolean 9 | } 10 | 11 | const CopyButton = ({handleCopy, isCopied} : propsType) => { 12 | return ( 13 | 36 | ) 37 | } 38 | 39 | export default CopyButton 40 | -------------------------------------------------------------------------------- /app/components/Resources.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | 3 | const Resources = () => { 4 | const resources = [ 5 | { link: { href: "#", label: "/api/products" }, title: "150 products" }, 6 | { link: { href: "#", label: "/api/users" }, title: "50 users" }, 7 | ]; 8 | 9 | return ( 10 |
11 |
12 |

Resources

13 |

14 | We offer access to two main resources through our REST API. 15 |

16 |
17 |
18 | {resources.map((resource) => ( 19 |
23 | 27 | {resource.link.label} 28 | 29 | {resource.title} 30 |
31 | ))} 32 |
33 |
34 | ) 35 | } 36 | 37 | export default Resources; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@radix-ui/react-scroll-area": "^1.0.5", 13 | "@radix-ui/react-slot": "^1.0.2", 14 | "@vercel/analytics": "^1.2.2", 15 | "class-variance-authority": "^0.7.0", 16 | "clsx": "^2.1.0", 17 | "framer-motion": "^11.0.5", 18 | "highlight.js": "^11.9.0", 19 | "lucide-react": "^0.325.0", 20 | "next": "14.1.0", 21 | "next-themes": "^0.2.1", 22 | "react": "^18", 23 | "react-dom": "^18", 24 | "react-icons": "^5.0.1", 25 | "react-multi-carousel": "^2.8.4", 26 | "react-scroll": "^1.9.0", 27 | "tailwind-merge": "^2.2.1", 28 | "tailwindcss-animate": "^1.0.7", 29 | "zod": "^3.22.4" 30 | }, 31 | "devDependencies": { 32 | "@types/node": "^20", 33 | "@types/prismjs": "^1.26.3", 34 | "@types/react": "^18", 35 | "@types/react-dom": "^18", 36 | "@types/react-scroll": "^1.8.10", 37 | "autoprefixer": "^10.0.1", 38 | "eslint": "^8", 39 | "eslint-config-next": "14.1.0", 40 | "postcss": "^8", 41 | "tailwindcss": "^3.3.0", 42 | "typescript": "^5" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/docs/users/AllUser.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Button } from "@/components/ui/button"; 4 | 5 | import { useState } from "react"; 6 | import { useTiggerHightlight } from "@/context/HighlightContext"; 7 | import { AllUsersOutputSnip, AllUsersSnip } from "./snippets"; 8 | 9 | const AllUser = () => { 10 | const [showOutput, setShowOutput] = useState(false); 11 | const { setTriggerHighlight } = useTiggerHightlight(); 12 | return ( 13 |
14 |
15 |

Get all users

16 | 17 |

18 | ⚡ Access all users by using{" "} 19 | 20 | /users?limit=20 21 | {" "} 22 | endpoint. 23 |

24 |
25 | 35 | {showOutput && } 36 |
37 | ); 38 | }; 39 | 40 | export default AllUser; 41 | -------------------------------------------------------------------------------- /app/docs/products/AllProducts.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Button } from "@/components/ui/button"; 4 | import { AllProductsOutputSnip, AllProductsSnip } from "./snippets"; 5 | import { useState } from "react"; 6 | import { useTiggerHightlight } from "@/context/HighlightContext"; 7 | 8 | const AllProducts = () => { 9 | const [showOutput, setShowOutput] = useState(false); 10 | const { setTriggerHighlight } = useTiggerHightlight(); 11 | return ( 12 |
13 |
14 |

Get all products

15 | 16 |

17 | ⚡ Access all products by using{" "} 18 | 19 | /products?limit=150 20 | {" "} 21 | endpoint. 22 |

23 |
24 | 34 | {showOutput && } 35 |
36 | ); 37 | }; 38 | 39 | export default AllProducts; 40 | -------------------------------------------------------------------------------- /app/hooks/useCopyToClipboard.tsx: -------------------------------------------------------------------------------- 1 | import { useRef, useState } from 'react'; 2 | 3 | export const useCopySnippet = () => { 4 | const snipRef = useRef(null); 5 | const [isCopied, setIsCopied] = useState(false); 6 | 7 | const handleCopy = async () => { 8 | const snippet = snipRef.current?.textContent; 9 | 10 | if (!navigator?.clipboard) { 11 | console.warn('Clipboard not supported') 12 | return 13 | } 14 | 15 | if (snippet) { 16 | try { 17 | await navigator.clipboard.writeText(snippet) 18 | setIsCopied(true); 19 | setTimeout(() => setIsCopied(false), 2000); 20 | } catch (err) { 21 | console.warn('Copy failed', err) 22 | } 23 | } 24 | } 25 | return { handleCopy, snipRef, isCopied }; 26 | } 27 | 28 | 29 | 30 | 31 | // type CopyFn = (text: string) => Promise 32 | // type returnType = {copy: CopyFn} 33 | 34 | // export function useCopyToClipboard(): returnType { 35 | 36 | // const copy: CopyFn = async text => { 37 | // if (!navigator?.clipboard) { 38 | // console.warn('Clipboard not supported') 39 | // return false 40 | // } 41 | 42 | // try { 43 | // await navigator.clipboard.writeText(text) 44 | // return true 45 | // } catch (error) { 46 | // console.warn('Copy failed', error) 47 | // return false 48 | // } 49 | // } 50 | // return {copy} 51 | // } -------------------------------------------------------------------------------- /app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import { Inter } from "next/font/google"; 3 | import "./globals.css"; 4 | import ThemeProvider from "./providers/ThemeProvider"; 5 | import Navbar from "./components/Navbar"; 6 | import { Analytics } from '@vercel/analytics/react'; 7 | 8 | const inter = Inter({ subsets: ["latin"] }); 9 | 10 | export const metadata: Metadata = { 11 | title: "fakeStoreApi - free products api", 12 | description: "fakeStoreApi is a free products API for testing and prototyping. It's a fake API with products that include images, prices, descriptions, and more. we also provide data for users where you can get all the users data and single user data.", 13 | keywords: "fakestoreapi, fake store api, free products api, fake api, fakestore api products fakeusersapi, fake users api, fake users data, fake users", 14 | 15 | }; 16 | 17 | export default function RootLayout({ 18 | children, 19 | }: Readonly<{ 20 | children: React.ReactNode; 21 | }>) { 22 | return ( 23 | 24 | 25 | 31 | 32 | {children} 33 | 34 | 35 | 36 | 37 | ) 38 | } 39 | -------------------------------------------------------------------------------- /app/api/products/category/route.ts: -------------------------------------------------------------------------------- 1 | import { NextRequest, NextResponse } from "next/server"; 2 | import { getProductsCategory } from "@helper/filterProducts"; 3 | import { createPayload } from "@helper/createPayload"; 4 | 5 | 6 | // method: GET 7 | // supported route: ["api/products/category", "api/products/category?type=tv&sort=desc&limit=20] 8 | // message: not necessary to apply all query 9 | 10 | export const GET = async (req: NextRequest) => { 11 | try { 12 | const type = req.nextUrl.searchParams.get("type") 13 | const sort = req.nextUrl.searchParams.get("sort") 14 | const limit = req.nextUrl.searchParams.get("limit") 15 | 16 | const {categories, products} = getProductsCategory({type, sort, limit}) 17 | if (categories) { 18 | const payload = createPayload({ 19 | status: "SUCCESS", 20 | message: "We have 6 categories to choose from.", 21 | categories: [...categories] 22 | }) 23 | return NextResponse.json(payload) 24 | } 25 | if (products) { 26 | const payload = createPayload({ 27 | status: 'SUCCESS', 28 | message: `You've received products from the ${products[0].category} category only.`, 29 | products 30 | }) 31 | return NextResponse.json(payload) 32 | } 33 | 34 | } catch (err: any) { 35 | const payload = createPayload({ 36 | status: "BAD-REQUEST", 37 | message: err.message, 38 | }) 39 | return NextResponse.json(payload, {status: 400}) 40 | } 41 | } -------------------------------------------------------------------------------- /app/components/About.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | import Image from "next/image"; 3 | import showcase from "../../public/showcase.jpg"; 4 | 5 | const About = () => { 6 | return ( 7 |
8 |
9 |

10 | Had enough of boring dummy data? 11 |

12 |

13 | We offer the finest free products API available. We've carefully 14 | selected top-notch product thumbnails and details to ensure websites 15 | built using our API stand out ✨. 16 |

17 |
18 | 19 |
20 | 21 |
22 | Illustration 29 |
30 | 31 |
32 |
33 | ); 34 | }; 35 | 36 | export default About; 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /app/components/Hero.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Image from "next/image"; 3 | import img from "../../public/Illustration.svg"; 4 | import { Button } from "@components/ui/button"; 5 | import Link from "next/link"; 6 | 7 | const Hero = () => { 8 | return ( 9 |
10 |
11 |
12 |

13 | E-commerce{" "} 14 | Prototyping Made Easy 15 |

16 |

17 | Build and test your e-commerce website or app seamlessly with our 18 | free and reliable Fake Store API. 19 |

20 |
21 | 29 | 32 |
33 |
34 |
35 |
36 | Illustration 42 |
43 |
44 |
45 |
46 | ); 47 | }; 48 | 49 | export default Hero; 50 | -------------------------------------------------------------------------------- /app/components/ui/scroll-area.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const ScrollArea = React.forwardRef< 9 | React.ElementRef, 10 | React.ComponentPropsWithoutRef 11 | >(({ className, children, ...props }, ref) => ( 12 | 17 | 18 | {children} 19 | 20 | 21 | 22 | 23 | )) 24 | ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName 25 | 26 | const ScrollBar = React.forwardRef< 27 | React.ElementRef, 28 | React.ComponentPropsWithoutRef 29 | >(({ className, orientation = "vertical", ...props }, ref) => ( 30 | 43 | 44 | 45 | )) 46 | ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName 47 | 48 | export { ScrollArea, ScrollBar } 49 | -------------------------------------------------------------------------------- /app/components/Navbar.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import Link from "next/link"; 4 | import { usePathname } from "next/navigation"; 5 | import { FiArrowUpRight } from "react-icons/fi"; 6 | import ToggleTheme from "./ToggleTheme"; 7 | import { cn } from "@/lib/utils"; 8 | 9 | const Navbar = () => { 10 | const pathname = usePathname() 11 | 12 | return ( 13 |
14 |
17 |
18 | 19 | FakeStoreAPI 20 | 21 |
22 |
23 |
    24 |
  • 27 | Home 28 |
  • 29 |
  • 32 | Docs 33 |
  • 34 |
  • 35 | 36 | GitHub 37 | 38 |
  • 39 |
40 | 41 |
42 |
43 |
44 | ) 45 | } 46 | 47 | export default Navbar; 48 | -------------------------------------------------------------------------------- /app/api/users/route.ts: -------------------------------------------------------------------------------- 1 | import { NextRequest, NextResponse } from "next/server"; 2 | import { totalUsers, getPaginatedUsers } from "@helper/filterUsers"; 3 | import { parseQuery } from "@helper/parseQuery"; 4 | import { parseRequestBody } from "@helper/parseRequestBody"; 5 | import { userSchema } from "@helper/schema"; 6 | import { createPayload } from "@helper/createPayload"; 7 | 8 | 9 | export const GET = async (req: NextRequest) => { 10 | try { 11 | const page_str = req.nextUrl.searchParams.get("page") 12 | const limit_str = req.nextUrl.searchParams.get("limit") || "20" 13 | const sort = req.nextUrl.searchParams.get("sort") 14 | const {page, limit} = parseQuery({page_str, limit_str}) 15 | const {users} = getPaginatedUsers({page, limit, sort}) 16 | 17 | const payload = createPayload({ 18 | status: "SUCCESS", 19 | message: `Here you go! You've received ${users.length} 20 | users.`, 21 | users 22 | }) 23 | 24 | return NextResponse.json(payload) 25 | } catch (err: any) { 26 | const payload = createPayload({ 27 | status: 'BAD-REQUEST', 28 | message: err.message, 29 | }) 30 | return NextResponse.json(payload, { status: 400 }) 31 | } 32 | } 33 | 34 | 35 | 36 | export const POST = async (request: NextRequest) => { 37 | try { 38 | const newUser = await parseRequestBody(request) 39 | const parsed = userSchema.parse(newUser) 40 | 41 | const payload = createPayload({ 42 | status: 'SUCCESS', 43 | message: `Here is the user you sent, which we have just returned 44 | you back. We do not save it in our Database`, 45 | user: {id: totalUsers + 1, ...parsed} 46 | }) 47 | 48 | return NextResponse.json(payload) 49 | } catch (err: any) { 50 | const payload = createPayload({ 51 | status: 'BAD-REQUEST', 52 | message: err.message, 53 | }) 54 | return NextResponse.json(payload, { status: 400 }) 55 | } 56 | } -------------------------------------------------------------------------------- /app/components/ui/button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { Slot } from "@radix-ui/react-slot" 3 | import { cva, type VariantProps } from "class-variance-authority" 4 | 5 | import { cn } from "@/lib/utils" 6 | 7 | const buttonVariants = cva( 8 | "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", 9 | { 10 | variants: { 11 | variant: { 12 | default: "bg-primary text-primary-foreground hover:bg-primary/90", 13 | destructive: 14 | "bg-destructive text-destructive-foreground hover:bg-destructive/90", 15 | outline: 16 | "border border-input bg-background hover:bg-accent hover:text-accent-foreground", 17 | secondary: 18 | "bg-secondary text-secondary-foreground hover:bg-secondary/80", 19 | ghost: "hover:bg-accent hover:text-accent-foreground", 20 | link: "text-primary underline-offset-4 hover:underline", 21 | }, 22 | size: { 23 | default: "h-10 px-4 py-2", 24 | sm: "h-9 rounded-md px-3", 25 | lg: "h-11 rounded-md px-8", 26 | icon: "h-10 w-10", 27 | }, 28 | }, 29 | defaultVariants: { 30 | variant: "default", 31 | size: "default", 32 | }, 33 | } 34 | ) 35 | 36 | export interface ButtonProps 37 | extends React.ButtonHTMLAttributes, 38 | VariantProps { 39 | asChild?: boolean 40 | } 41 | 42 | const Button = React.forwardRef( 43 | ({ className, variant, size, asChild = false, ...props }, ref) => { 44 | const Comp = asChild ? Slot : "button" 45 | return ( 46 | 51 | ) 52 | } 53 | ) 54 | Button.displayName = "Button" 55 | 56 | export { Button, buttonVariants } 57 | -------------------------------------------------------------------------------- /app/api/products/route.ts: -------------------------------------------------------------------------------- 1 | import { NextRequest, NextResponse } from "next/server"; 2 | import { totalProducts, getPaginatedProducts } from "@helper/filterProducts"; 3 | import { parseQuery } from "@helper/parseQuery"; 4 | import { parseRequestBody } from "@helper/parseRequestBody"; 5 | import { productSchema } from "@helper/schema"; 6 | import { createPayload } from "@helper/createPayload"; 7 | 8 | 9 | // method: GET 10 | // supported route: ["api/products", "api/products?page=1&limit=50"] 11 | // message: not necessary to apply all query 12 | 13 | export const GET = async (req: NextRequest) => { 14 | try { 15 | const page_str = req.nextUrl.searchParams.get("page") 16 | const limit_str = req.nextUrl.searchParams.get("limit") 17 | const {page, limit} = parseQuery({page_str, limit_str}) 18 | const { products} = getPaginatedProducts({page, limit}) 19 | 20 | const payload = createPayload({ 21 | status: "SUCCESS", 22 | message: `Here you go! You've received ${products.length} 23 | products. If you need more, just ask for it`, 24 | products 25 | }) 26 | 27 | return NextResponse.json(payload) 28 | } catch (err: any) { 29 | const payload = createPayload({ 30 | status: 'BAD-REQUEST', 31 | message: err.message, 32 | }) 33 | return NextResponse.json(payload, { status: 400 }) 34 | } 35 | } 36 | 37 | 38 | // method: POST 39 | // supported route: ["api/products"] 40 | 41 | export const POST = async (request: NextRequest) => { 42 | try { 43 | const newProduct = await parseRequestBody(request) 44 | const parsed = productSchema.parse(newProduct) 45 | 46 | const payload = createPayload({ 47 | status: 'SUCCESS', 48 | message: `Here is the product you sent, which we have just returned 49 | you back. We do not save it in our Database`, 50 | product: {id: totalProducts + 1, ...parsed} 51 | }) 52 | 53 | return NextResponse.json(payload) 54 | } catch (err: any) { 55 | const payload = createPayload({ 56 | status: 'BAD-REQUEST', 57 | message: err.message, 58 | }) 59 | return NextResponse.json(payload, { status: 400 }) 60 | } 61 | } -------------------------------------------------------------------------------- /app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | html { 6 | scroll-behavior: smooth; 7 | } 8 | 9 | *::selection { 10 | background-color: #ec489a9c; 11 | color: white; 12 | } 13 | 14 | html.dark *::selection { 15 | background-color: #1d2021; 16 | } 17 | 18 | 19 | @layer base { 20 | :root { 21 | --background: 0 0% 100%; 22 | --foreground: 222.2 84% 4.9%; 23 | 24 | --card: 0 0% 100%; 25 | --card-foreground: 222.2 84% 4.9%; 26 | 27 | --popover: 0 0% 100%; 28 | --popover-foreground: 222.2 84% 4.9%; 29 | 30 | --primary: 222.2 47.4% 11.2%; 31 | --primary-foreground: 210 40% 98%; 32 | 33 | --secondary: 210 40% 96.1%; 34 | --secondary-foreground: 222.2 47.4% 11.2%; 35 | 36 | --muted: 210 40% 96.1%; 37 | --muted-foreground: 215.4 16.3% 46.9%; 38 | 39 | --accent: 210 40% 96.1%; 40 | --accent-foreground: 222.2 47.4% 11.2%; 41 | 42 | --destructive: 0 84.2% 60.2%; 43 | --destructive-foreground: 210 40% 98%; 44 | 45 | --border: 214.3 31.8% 91.4%; 46 | --input: 214.3 31.8% 91.4%; 47 | --ring: 222.2 84% 4.9%; 48 | 49 | --radius: 0.5rem; 50 | } 51 | 52 | .dark { 53 | --background: 222.2 84% 4.9%; 54 | --foreground: 210 40% 98%; 55 | 56 | --card: 222.2 84% 4.9%; 57 | --card-foreground: 210 40% 98%; 58 | 59 | --popover: 222.2 84% 4.9%; 60 | --popover-foreground: 210 40% 98%; 61 | 62 | --primary: 210 40% 98%; 63 | --primary-foreground: 222.2 47.4% 11.2%; 64 | 65 | --secondary: 217.2 32.6% 17.5%; 66 | --secondary-foreground: 210 40% 98%; 67 | 68 | --muted: 217.2 32.6% 17.5%; 69 | --muted-foreground: 215 20.2% 65.1%; 70 | 71 | --accent: 217.2 32.6% 17.5%; 72 | --accent-foreground: 210 40% 98%; 73 | 74 | --destructive: 0 62.8% 30.6%; 75 | --destructive-foreground: 210 40% 98%; 76 | 77 | --border: 217.2 32.6% 17.5%; 78 | --input: 217.2 32.6% 17.5%; 79 | --ring: 212.7 26.8% 83.9%; 80 | } 81 | } 82 | 83 | @layer base { 84 | * { 85 | @apply border-border; 86 | } 87 | body { 88 | @apply bg-background text-foreground; 89 | } 90 | } -------------------------------------------------------------------------------- /app/api/helper/filterUsers.ts: -------------------------------------------------------------------------------- 1 | import { Users } from '@data/user/users' 2 | export const totalUsers = Users.length 3 | 4 | type filterType = { 5 | page: number | null; 6 | limit: number | null; 7 | sort: string | null; 8 | } 9 | 10 | export const getSingleUser = (id: number) => { 11 | if (Number.isNaN(id)) throw new Error("Oops! only numeric characters are allowed.") 12 | const filteredUsers = Users.filter(user => user.id === id) 13 | if (filteredUsers.length > 0) return filteredUsers[0] 14 | else return Users[totalUsers - 1] 15 | } 16 | 17 | 18 | export const getPaginatedUsers = (filter: filterType) => { 19 | const page = filter.page ?? 1; 20 | const limit = filter.limit ?? 50; 21 | const sort = filter.sort; 22 | const skip = (page - 1) * limit; 23 | const totalPages = Math.ceil(totalUsers / limit); 24 | 25 | let usersCopy = [...Users]; 26 | 27 | if (skip >= totalUsers) { 28 | const lastPageSkip = (totalPages - 1) * limit; 29 | usersCopy = usersCopy.slice(lastPageSkip); 30 | } else { 31 | usersCopy = usersCopy.slice(skip, skip + limit); 32 | } 33 | 34 | if (sort !== null) { 35 | if (!['desc', 'asc'].includes(sort)) { 36 | throw new Error("Sort type must be 'desc' or 'asc'."); 37 | } 38 | switch (sort) { 39 | case "desc": 40 | usersCopy.sort((a, b) => b.id - a.id); 41 | break; 42 | case "asc": 43 | usersCopy.sort((a, b) => a.id - b.id); 44 | break; 45 | } 46 | } 47 | 48 | return { users: usersCopy }; 49 | }; 50 | 51 | 52 | 53 | export const getUsersSort = (sort: string | null) => { 54 | if (sort !== null) { 55 | if (!['desc', 'asc'].includes(sort)) { 56 | throw new Error("Sort type must be 'desc' or 'asc'."); 57 | } 58 | } 59 | 60 | let users = Users; 61 | 62 | switch (sort) { 63 | case "desc": 64 | users.sort((a, b) => b.id - a.id); 65 | break; 66 | case "asc": 67 | users.sort((a, b) => a.id - b.id); 68 | break; 69 | } 70 | 71 | return {users} 72 | } 73 | -------------------------------------------------------------------------------- /app/api/helper/filterProducts.ts: -------------------------------------------------------------------------------- 1 | import { Products } from '@data/product/products' 2 | export const totalProducts = Products.length 3 | 4 | type filterType = { 5 | page: number | null; 6 | limit: number | null; 7 | } 8 | type categoryType = { 9 | type: string | null; 10 | sort: string | null; 11 | limit: string | null; 12 | } 13 | 14 | export const getSingleProduct = (id: number) => { 15 | if (Number.isNaN(id)) throw new Error("Oops! only numeric characters are allowed.") 16 | const filteredProducts = Products.filter(product => product.id === id) 17 | if (filteredProducts.length > 0) return filteredProducts[0] 18 | else return Products[totalProducts - 1] 19 | } 20 | 21 | export const getPaginatedProducts = (filter : filterType) => { 22 | const page = filter.page ?? 1; 23 | const limit = filter.limit ?? 50; 24 | const skip = (page - 1) * limit; 25 | const totalPages = Math.ceil(totalProducts / limit); 26 | 27 | if (skip >= totalProducts) { 28 | // Return the last page if the requested page exceeds the available data 29 | const lastPageSkip = (totalPages - 1) * limit; 30 | const products = Products.slice(lastPageSkip); 31 | return {products} 32 | 33 | } else { 34 | const products = Products.slice(skip, skip + limit); 35 | return {products} 36 | } 37 | } 38 | 39 | 40 | export const getProductsCategory = (category: categoryType) => { 41 | const categories = ["tv", "audio", "laptop", "mobile", "gaming", "appliances"]; 42 | 43 | if (category.type === null) { 44 | return { categories }; 45 | } 46 | if (!categories.includes(category.type)) { 47 | throw new Error("Category type must be within the defined categories."); 48 | } 49 | if (category.sort !== null) { 50 | if (!['desc', 'asc'].includes(category.sort)) { 51 | throw new Error("Sort type must be 'desc' or 'asc'."); 52 | } 53 | } 54 | 55 | let products = Products.filter((product) => product.category === category.type); 56 | 57 | switch (category.sort) { 58 | case "desc": 59 | products.sort((a, b) => b.price - a.price); 60 | break; 61 | case "asc": 62 | products.sort((a, b) => a.price - b.price); 63 | break; 64 | } 65 | 66 | if (category.limit && parseInt(category.limit)) { 67 | products = products.slice(0, Number(category.limit)); 68 | } 69 | return { products }; 70 | }; 71 | 72 | -------------------------------------------------------------------------------- /tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss" 2 | 3 | const config = { 4 | darkMode: ["class"], 5 | content: [ 6 | './pages/**/*.{ts,tsx}', 7 | './components/**/*.{ts,tsx}', 8 | './app/**/*.{ts,tsx}', 9 | './src/**/*.{ts,tsx}', 10 | ], 11 | prefix: "", 12 | theme: { 13 | container: { 14 | center: true, 15 | padding: "2rem", 16 | screens: { 17 | "2xl": "1400px", 18 | }, 19 | }, 20 | extend: { 21 | colors: { 22 | border: "hsl(var(--border))", 23 | input: "hsl(var(--input))", 24 | ring: "hsl(var(--ring))", 25 | background: "hsl(var(--background))", 26 | foreground: "hsl(var(--foreground))", 27 | primary: { 28 | DEFAULT: "hsl(var(--primary))", 29 | foreground: "hsl(var(--primary-foreground))", 30 | }, 31 | secondary: { 32 | DEFAULT: "hsl(var(--secondary))", 33 | foreground: "hsl(var(--secondary-foreground))", 34 | }, 35 | destructive: { 36 | DEFAULT: "hsl(var(--destructive))", 37 | foreground: "hsl(var(--destructive-foreground))", 38 | }, 39 | muted: { 40 | DEFAULT: "hsl(var(--muted))", 41 | foreground: "hsl(var(--muted-foreground))", 42 | }, 43 | accent: { 44 | DEFAULT: "hsl(var(--accent))", 45 | foreground: "hsl(var(--accent-foreground))", 46 | }, 47 | popover: { 48 | DEFAULT: "hsl(var(--popover))", 49 | foreground: "hsl(var(--popover-foreground))", 50 | }, 51 | card: { 52 | DEFAULT: "hsl(var(--card))", 53 | foreground: "hsl(var(--card-foreground))", 54 | }, 55 | }, 56 | borderRadius: { 57 | lg: "var(--radius)", 58 | md: "calc(var(--radius) - 2px)", 59 | sm: "calc(var(--radius) - 4px)", 60 | }, 61 | keyframes: { 62 | "accordion-down": { 63 | from: { height: "0" }, 64 | to: { height: "var(--radix-accordion-content-height)" }, 65 | }, 66 | "accordion-up": { 67 | from: { height: "var(--radix-accordion-content-height)" }, 68 | to: { height: "0" }, 69 | }, 70 | }, 71 | animation: { 72 | "accordion-down": "accordion-down 0.2s ease-out", 73 | "accordion-up": "accordion-up 0.2s ease-out", 74 | }, 75 | gridTemplateColumns: { 76 | "30%-1fr": "30% 1fr" 77 | } 78 | }, 79 | }, 80 | plugins: [require("tailwindcss-animate")], 81 | } satisfies Config 82 | 83 | export default config -------------------------------------------------------------------------------- /app/docs/Sidebar.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { ScrollArea } from "@components/ui/scroll-area"; 4 | import { GoPackage } from "react-icons/go"; 5 | import { TbUsers } from "react-icons/tb"; 6 | import { Link } from "react-scroll/modules"; 7 | 8 | const Sidebar = () => { 9 | const productsTabs = [ 10 | { section: "Get all products", link: "all_products" }, 11 | { section: "Get a single product", link: "single_product" }, 12 | { section: "Limit products", link: "limit_products" }, 13 | { section: "Pagination", link: "product_pagination" }, 14 | { section: "Get categories", link: "products_category" }, 15 | { section: "Get products of category", link: "products_of_category" }, 16 | { section: "Add a product", link: "add_product" }, 17 | { section: "Update a product", link: "update_product" }, 18 | { section: "Delete a product", link: "delete_product" }, 19 | ]; 20 | const usersTabs = [ 21 | { section: "Get all users", link: "all_users" }, 22 | { section: "Get a single user", link: "single_users" }, 23 | { section: "Limit users", link: "limit_users" }, 24 | { section: "Pagination", link: "users_pagination" }, 25 | { section: "Add a user", link: "add_users" }, 26 | { section: "Update a user", link: "update_users" }, 27 | { section: "Delete a user", link: "delete_users" }, 28 | ]; 29 | 30 | return ( 31 | 32 |

33 | Products 34 |

35 |
    36 | {productsTabs.map((tab) => ( 37 |
  • 38 | 45 | {tab.section} 46 | 47 |
  • 48 | ))} 49 |
50 |

51 | Users 52 |

53 |
    54 | {usersTabs.map((tab) => ( 55 |
  • 56 | 63 | {tab.section} 64 | 65 |
  • 66 | ))} 67 |
68 |
69 | ); 70 | }; 71 | 72 | export default Sidebar; 73 | -------------------------------------------------------------------------------- /app/api/products/[id]/route.ts: -------------------------------------------------------------------------------- 1 | import { NextRequest, NextResponse } from "next/server"; 2 | import { getSingleProduct } from "@helper/filterProducts"; 3 | import { parseRequestBody } from "@helper/parseRequestBody"; 4 | import { productSchema } from "@helper/schema"; 5 | import { createPayload } from "@helper/createPayload"; 6 | 7 | 8 | // method: GET 9 | // supported route: ["api/products/:id"] 10 | // message: returns the last product if the requested product not found. 11 | 12 | export const GET = async (request: NextRequest, {params} : {params: {id: string}}) => { 13 | try { 14 | const { id } = params; 15 | const product = getSingleProduct(parseInt(id)) 16 | const payload = createPayload({ 17 | status: 'SUCCESS', 18 | message: `Here you've a single product requested for id ${parseInt(id)}`, 19 | product 20 | }) 21 | return NextResponse.json(payload) 22 | } catch (err: any) { 23 | const payload = createPayload({ 24 | status: 'BAD-REQUEST', 25 | message: err.message, 26 | }) 27 | return NextResponse.json(payload, {status: 400}) 28 | } 29 | } 30 | 31 | 32 | // method: PUT 33 | // supported route: ["api/products/:id"] 34 | 35 | export const PUT = async (request: NextRequest, {params} : {params: {id: string}}) => { 36 | try { 37 | const { id } = params; 38 | const product = await parseRequestBody(request) 39 | const parsed = productSchema.parse(product) 40 | const payload = createPayload({ 41 | status: "SUCCESS", 42 | message: `The product with id ${parseInt(id)} has been replaced with your provided data`, 43 | product: {id, ...parsed} 44 | }) 45 | return NextResponse.json(payload) 46 | } catch (err: any) { 47 | const payload = createPayload({ 48 | status: 'BAD-REQUEST', 49 | message: err.message, 50 | }) 51 | return NextResponse.json(payload, { status: 400 }) 52 | } 53 | } 54 | 55 | 56 | // method: PATCH 57 | // supported route: ["api/products/:id"] 58 | 59 | export const PATCH = async (request: NextRequest, {params} : {params: {id: string}}) => { 60 | try { 61 | const { id } = params; 62 | const productToUpdate = await parseRequestBody(request) 63 | const product = getSingleProduct(parseInt(id)) 64 | const parsed = productSchema.parse(productToUpdate) 65 | const payload = createPayload({ 66 | status: 'SUCCESS', 67 | message: `The product with id ${parseInt(id)} has been updated with your provided data`, 68 | product: {...product, ...parsed} 69 | }) 70 | return NextResponse.json(payload) 71 | } catch (err: any) { 72 | const payload = createPayload({ 73 | status: 'BAD-REQUEST', 74 | message: err.message, 75 | }) 76 | return NextResponse.json(payload, { status: 400 }) 77 | } 78 | } 79 | 80 | 81 | // method: DELETE 82 | // supported route: ["api/products/:id"] 83 | 84 | export const DELETE = async (request: NextRequest, {params} : {params: {id: string}}) => { 85 | try { 86 | const { id } = params; 87 | const payload = createPayload({ 88 | status: 'SUCCESS', 89 | message: `Product with id ${parseInt(id)} has been deleted`, 90 | }) 91 | return NextResponse.json(payload) 92 | } catch (err: any) { 93 | const payload = createPayload({ 94 | status: 'BAD-REQUEST', 95 | message: err.message, 96 | }) 97 | return NextResponse.json(payload, { status: 400 }) 98 | } 99 | } -------------------------------------------------------------------------------- /app/api/users/[id]/route.ts: -------------------------------------------------------------------------------- 1 | import { NextRequest, NextResponse } from "next/server"; 2 | import { getSingleUser } from "@helper/filterUsers"; 3 | import { parseRequestBody } from "@helper/parseRequestBody"; 4 | import { userSchema } from "@helper/schema"; 5 | import { createPayload } from "@helper/createPayload"; 6 | 7 | 8 | // method: GET 9 | // supported route: ["api/users/:id"] 10 | // message: returns the last user if the requested user not found. 11 | 12 | export const GET = async (request: NextRequest, {params} : {params: {id: string}}) => { 13 | try { 14 | const { id } = params; 15 | const user = getSingleUser(parseInt(id)) 16 | const payload = createPayload({ 17 | status: 'SUCCESS', 18 | message: `Here you've a single user requested for id ${parseInt(id)}`, 19 | user 20 | }) 21 | return NextResponse.json(payload) 22 | } catch (err: any) { 23 | const payload = createPayload({ 24 | status: 'BAD-REQUEST', 25 | message: err.message, 26 | }) 27 | return NextResponse.json(payload, {status: 400}) 28 | } 29 | } 30 | 31 | 32 | // method: PUT 33 | // supported route: ["api/users/:id"] 34 | 35 | export const PUT = async (request: NextRequest, {params} : {params: {id: string}}) => { 36 | try { 37 | const { id } = params; 38 | const userToUpdate = await parseRequestBody(request) 39 | const user = getSingleUser(parseInt(id)) 40 | const parsed = userSchema.parse(userToUpdate) 41 | const payload = createPayload({ 42 | status: 'SUCCESS', 43 | message: `The user with id ${parseInt(id)} has been updated with your provided data`, 44 | user: {...user, ...parsed} 45 | }) 46 | return NextResponse.json(payload) 47 | } catch (err: any) { 48 | const payload = createPayload({ 49 | status: 'BAD-REQUEST', 50 | message: err.message, 51 | }) 52 | return NextResponse.json(payload, { status: 400 }) 53 | } 54 | } 55 | 56 | // method: PATCH 57 | // supported route: ["api/users/:id"] 58 | 59 | export const PATCH = async (request: NextRequest, {params} : {params: {id: string}}) => { 60 | try { 61 | const { id } = params; 62 | const userToUpdate = await parseRequestBody(request) 63 | const user = getSingleUser(parseInt(id)) 64 | const parsed = userSchema.parse(userToUpdate) 65 | const payload = createPayload({ 66 | status: 'SUCCESS', 67 | message: `The user with id ${parseInt(id)} has been updated with your provided data`, 68 | user: {...user, ...parsed} 69 | }) 70 | return NextResponse.json(payload) 71 | } catch (err: any) { 72 | const payload = createPayload({ 73 | status: 'BAD-REQUEST', 74 | message: err.message, 75 | }) 76 | return NextResponse.json(payload, { status: 400 }) 77 | } 78 | } 79 | 80 | // method: DELETE 81 | // supported route: ["api/users/:id"] 82 | 83 | 84 | 85 | export const DELETE = async (request: NextRequest, {params} : {params: {id: string}}) => { 86 | try { 87 | const { id } = params; 88 | const payload = createPayload({ 89 | status: 'SUCCESS', 90 | message: `User with id ${parseInt(id)} has been deleted`, 91 | }) 92 | return NextResponse.json(payload) 93 | } catch (err: any) { 94 | const payload = createPayload({ 95 | status: 'BAD-REQUEST', 96 | message: err.message, 97 | }) 98 | return NextResponse.json(payload, { status: 400 }) 99 | } 100 | } -------------------------------------------------------------------------------- /app/components/Route.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils"; 2 | import Link from "next/link"; 3 | 4 | const Route = () => { 5 | const routes = [ 6 | { 7 | method: "GET", 8 | link: { 9 | href: "https://fakestoreapi.in/api/products" 10 | , 11 | label: "https://fakestoreapi.in/api/products", 12 | }, 13 | }, 14 | { 15 | method: "GET", 16 | link: { 17 | href: "https://fakestoreapi.in/api/products/1", 18 | label: "https://fakestoreapi.in/api/products/1", 19 | }, 20 | }, 21 | { 22 | method: "GET", 23 | link: { 24 | href: "https://fakestoreapi.in/api/products?page=2", 25 | label: "https://fakestoreapi.in/api/products?page=2", 26 | }, 27 | }, 28 | { 29 | method: "GET", 30 | link: { 31 | href: "https://fakestoreapi.in/api/products?limit=20", 32 | label: "https://fakestoreapi.in/api/products?limit=20", 33 | }, 34 | }, 35 | { 36 | method: "GET", 37 | link: { 38 | href: "https://fakestoreapi.in/api/products/category", 39 | label: "https://fakestoreapi.in/api/products/category", 40 | }, 41 | }, 42 | { 43 | method: "GET", 44 | link: { 45 | href: "https://fakestoreapi.in/api/products/category?type=mobile", 46 | label: "https://fakestoreapi.in/api/products/category?type=mobile", 47 | }, 48 | }, 49 | { 50 | method: "GET", 51 | link: { 52 | href: "https://fakestoreapi.in/api/products/category?type=tv&sort=desc", 53 | label: 54 | "https://fakestoreapi.in/api/products/category?type=tv&sort=desc", 55 | }, 56 | }, 57 | { 58 | method: "POST", 59 | link: { 60 | href: "https://fakestoreapi.in/api/products", 61 | label: "https://fakestoreapi.in/api/products", 62 | }, 63 | }, 64 | { 65 | method: "PUT", 66 | link: { 67 | href: "https://fakestoreapi.in/api/products/5", 68 | label: "https://fakestoreapi.in/api/products/5", 69 | }, 70 | }, 71 | { 72 | method: "PATCH", 73 | link: { 74 | href: "https://fakestoreapi.in/api/products/7", 75 | label: "https://fakestoreapi.in/api/products/7", 76 | }, 77 | }, 78 | { 79 | method: "DELETE", 80 | link: { 81 | href: "https://fakestoreapi.in/api/products/3", 82 | label: "https://fakestoreapi.in/api/products/3", 83 | }, 84 | }, 85 | ]; 86 | 87 | return ( 88 |
89 |
90 |

Routes

91 |

All HTTP methods are supported.

92 |
93 |
94 | {routes.map((route) => ( 95 |
99 | 107 | {route.method} 108 | 109 | 118 | {route.link.label} 119 | 120 |
121 | ))} 122 |
123 |
124 | ); 125 | }; 126 | 127 | export default Route; 128 | -------------------------------------------------------------------------------- /app/docs/users/snippets.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useCopySnippet } from "@/hooks/useCopyToClipboard" 4 | import CopyButton from "@/components/CopyButton" 5 | import {motion} from 'framer-motion' 6 | 7 | export const AllUsersSnip = () => { 8 | const {snipRef, handleCopy, isCopied} = useCopySnippet() 9 | 10 | return ( 11 |
 12 |           
 13 | {`fetch("https://fakestoreapi.in/api/users")
 14 | .then(res => res.json())
 15 | .then(res => console.log(res))
 16 | `}          
 17 |           
 18 |           
 19 |         
20 | ) 21 | } 22 | export const AllUsersOutputSnip = () => { 23 | 24 | return ( 25 |
26 | 31 |
 32 |           
 33 |           {`
 34 |     {
 35 |         "status": "SUCCESS",
 36 |         "message": "Here you go! You've received 20 users.",
 37 |         "users": [
 38 |           {
 39 |             "id": 1,
 40 |             "email": "michael@simpson.com",
 41 |             "username": "michaelsimpson",
 42 |             "password": "@K(5UejhL&",
 43 |             "name": {
 44 |               "firstname": "Michael",
 45 |               "lastname": "Simpson"
 46 |             },
 47 |             "address": {
 48 |               "city": "Joelton",
 49 |               "street": "Angela Spring",
 50 |               "number": "868",
 51 |               "zipcode": "75070",
 52 |               "geolocation": {
 53 |                 "lat": 19.7091875,
 54 |                 "long": -14.782061
 55 |               }
 56 |             },
 57 |             "phone": "562.548.9768x73853"
 58 |           },
 59 |           //{...}
 60 |           {
 61 |             "id": 20,
 62 |             "email": "timothy@burton.com",
 63 |             "username": "timothyburton",
 64 |             "password": "&$)QeGpZ25",
 65 |             "name": {
 66 |               "firstname": "Timothy",
 67 |               "lastname": "Burton"
 68 |             },
 69 |             "address": {
 70 |               "geolocation": {...}
 71 |             },
 72 |             "phone": "+1-293-912-5353x125"
 73 |           }
 74 |         ]
 75 |       }
 76 |         `}     
 77 |           
 78 |         
79 |
80 | ) 81 | } 82 | export const SingleUserSnip = () => { 83 | const {snipRef, handleCopy, isCopied} = useCopySnippet() 84 | 85 | return ( 86 |
 87 |           
 88 | {`fetch("https://fakestoreapi.in/api/users/7") 
 89 | .then(res => res.json())
 90 | .then(res => console.log(res))
 91 | `}          
 92 |           
 93 |           
 94 |         
95 | ) 96 | } 97 | export const SingleUserOutputSnip = () => { 98 | 99 | return ( 100 |
101 | 106 |
107 |           
108 |         {`
109 |    {
110 |     "status": "SUCCESS",
111 |     "message": "Here you've a single user requested for id 7",
112 |     "user": {
113 |       "id": 7,
114 |       "email": "tracy@frey.com",
115 |       "username": "tracyfrey",
116 |       "password": "#y5ITp+_(C",
117 |       "name": {
118 |         "firstname": "Tracy",
119 |         "lastname": "Frey"
120 |       },
121 |       "address": {
122 |         "city": "East Mary",
123 |         "street": "Tracey Trace",
124 |         "number": "107",
125 |         "zipcode": "16482",
126 |         "geolocation": {
127 |           "lat": -0.870534,
128 |           "long": -98.235893
129 |         }
130 |       },
131 |       "phone": "493.409.0584"
132 |     }
133 |   }
134 |         `}
135 |           
136 |         
137 |
138 | ) 139 | } 140 | export const LimitedUserSnip = () => { 141 | const {snipRef, handleCopy, isCopied} = useCopySnippet() 142 | 143 | return ( 144 |
145 |           
146 | {`fetch("https://fakestoreapi.in/api/users?limit=2") 
147 | .then(res => res.json())
148 | .then(res => console.log(res))
149 | `}          
150 |           
151 |           
152 |         
153 | ) 154 | } 155 | export const LimitedUserOutputSnip = () => { 156 | 157 | return ( 158 |
159 | 164 |
165 |           
166 |         {`
167 |      {
168 |         "status": "SUCCESS",
169 |         "message": "Here you go! You've received 2 users.",
170 |         "users": [
171 |           {
172 |             "id": 1,
173 |             "email": "michael@simpson.com",
174 |             "username": "michaelsimpson",
175 |             "password": "@K(5UejhL&",
176 |             "name": {...},
177 |             "address": {...},
178 |             "phone": "562.548.9768x73853"
179 |           },
180 |           {
181 |             "id": 2,
182 |             "email": "april@boyd.com",
183 |             "username": "aprilboyd",
184 |             "password": "k8WR_hX0+m",
185 |             "name": {...},
186 |             "address": {...},
187 |             "phone": "9329508218"
188 |           }
189 |         ]
190 |       }
191 |         `}
192 |           
193 |         
194 |
195 | ) 196 | } 197 | export const PaginationSnip = () => { 198 | const {snipRef, handleCopy, isCopied} = useCopySnippet() 199 | 200 | return ( 201 | <>
202 |           
203 | {`fetch("https://fakestoreapi.in/api/users?page=2")
204 | .then(res => res.json())
205 | .then(res => console.log(res))
206 | `}          
207 |           
208 |           
209 |         
210 |
211 |

212 | ⚡ By default, we send 20 users. use{" "} 213 | 214 | /users?page=2&limit=20 215 | {" "} 216 | to limit users per page. 217 |

218 |

219 | {/* 💁‍♂️ You don't need to pass{" "} */} 220 | 221 | ?skip=20 222 | {" "} 223 | query, we took care of that. 224 |

225 |
226 | 227 | ) 228 | } 229 | export const PaginationOutputSnip = () => { 230 | 231 | return ( 232 |
233 | 238 |
239 |           
240 |         {`
241 |    {
242 |     "status": "SUCCESS",
243 |     "message": "Here you go! You've received 20 users.",
244 |     "users": [
245 |       {
246 |         "id": 21,
247 |         "email": "destiny@powers.com",
248 |         "username": "destinypowers",
249 |         "password": "h6I6La6H2(",
250 |         "name": {...},
251 |         "address": {...},
252 |         "phone": "(725)466-6824"
253 |       },
254 |       //{...}
255 |       {
256 |         "id": 40,
257 |         "email": "lisa@underwood.com",
258 |         "username": "lisaunderwood",
259 |         "password": "Lt7R*0Go^@",
260 |         "name": {...},
261 |         "address": {...},
262 |         "phone": "(392)603-8492"
263 |       }
264 |     ]
265 |   }
266 |         `}
267 |           
268 |         
269 |
270 | ) 271 | } 272 | export const AddUserSnip = () => { 273 | const {snipRef, handleCopy, isCopied} = useCopySnippet() 274 | 275 | return ( 276 |
277 |           
278 |    {`fetch("https://fakestoreapi.in/api/users", {
279 |     method: 'POST',
280 |     headers: { 'Content-Type': 'application/json' },
281 |     body: JSON.stringify({
282 |         "email": "Thala@seven.com",
283 |         "username": "MSDhoni",
284 |         "password": "@2011WC",
285 |         "name": {
286 |           "firstname": "Mahendra Singh",
287 |           "lastname": "Dhoni"
288 |         },
289 |         "address": {
290 |           "city": "Rachi",
291 |           "street": "Local Boy",
292 |           "number": "7777777",
293 |           "zipcode": "7777",
294 |           "geolocation": {
295 |             "lat": 77.77777,
296 |             "long": 77.77777
297 |           }
298 |         },
299 |         "phone": "777777777"
300 |     })
301 |   })
302 |   `}          
303 |           
304 |           
305 |         
306 | ) 307 | } 308 | export const AddUserOutputSnip = () => { 309 | 310 | return ( 311 |
312 | 317 |
318 |           
319 |         {`
320 | {
321 |     "status": "SUCCESS",
322 |     "message": "Here is the user you sent, which we have just returned you back...",
323 |     "user": {
324 |       "id": 51,
325 |       "email": "Thala@seven.com",
326 |       "username": "MSDhoni",
327 |       "password": "@2011WC",
328 |       "name": {
329 |         "firstname": "Mahendra Singh",
330 |         "lastname": "Dhoni"
331 |       },
332 |       "address": {
333 |         "city": "Rachi",
334 |         "street": "Local Boy",
335 |         "number": "7777777",
336 |         "zipcode": "7777",
337 |         "geolocation": {
338 |           "lat": 77.77777,
339 |           "long": 77.77777
340 |         }
341 |       },
342 |       "phone": "777777777"
343 |     }
344 |   }
345 |         `}
346 |           
347 |         
348 |
349 | ) 350 | } 351 | export const UpdateUserSnip = () => { 352 | const {snipRef, handleCopy, isCopied} = useCopySnippet() 353 | 354 | return ( 355 |
356 |           
357 |    {`fetch("https://fakestoreapi.in/api/users/18", {
358 |     method: 'PUT',
359 |     headers: { 'Content-Type': 'application/json' },
360 |     body: JSON.stringify({
361 |         "email": "Virat@king.com",
362 |         "username": "Viratkholi",
363 |         "password": "@ESALEECUPNAMDE",
364 |         "name": {
365 |           "firstname": "Virat",
366 |           "lastname": "Kohli"
367 |         },
368 |         "address": {
369 |           "city": "Delhi",
370 |           "street": "Local Boy",
371 |           "number": "181818",
372 |           "zipcode": "181818",
373 |           "geolocation": {
374 |             "lat": 18.1818,
375 |             "long": 18.181818
376 |           }
377 |         },
378 |         "phone": "18181818"
379 |     })
380 |   })
381 | `}          
382 |           
383 |           
384 |         
385 | ) 386 | } 387 | export const UpdateUserOutputSnip = () => { 388 | 389 | return ( 390 |
391 | 396 |
397 |           
398 |         {`
399 | {
400 |     "status": "SUCCESS",
401 |     "message": "The user with id 18 has been updated with your provided data",
402 |     "user": {
403 |       "id": 18,
404 |       "email": "Virat@king.com",
405 |       "username": "Viratkholi",
406 |       "password": "@ESALEECUPNAMDE",
407 |       "name": {
408 |         "firstname": "Virat",
409 |         "lastname": "Kohli"
410 |       },
411 |       "address": {
412 |         "city": "Delhi",
413 |         "street": "Local Boy",
414 |         "number": "181818",
415 |         "zipcode": "181818",
416 |         "geolocation": {
417 |           "lat": 18.1818,
418 |           "long": 18.181818
419 |         }
420 |       },
421 |       "phone": "18181818"
422 |     }
423 |   }
424 |  `}
425 |           
426 |         
427 |
428 | ) 429 | } 430 | export const DeleteUserSnip = () => { 431 | const {snipRef, handleCopy, isCopied} = useCopySnippet() 432 | 433 | return ( 434 |
435 |           
436 | {`fetch("https://fakestoreapi.in/api/users/11", {
437 | method: 'DELETE',
438 | }).then(res => res.json())
439 | .then(res => console.log(res))
440 | `}          
441 |           
442 |           
443 |         
444 | ) 445 | } 446 | export const DeleteUserOutputSnip = () => { 447 | 448 | return ( 449 |
450 | 455 |
456 |           
457 |         {`
458 | {
459 |     "status": "SUCCESS",
460 |     "message": "User with id 11 has been deleted"
461 |   }
462 |  `}
463 |           
464 |         
465 |
466 | ) 467 | } -------------------------------------------------------------------------------- /app/docs/products/snippets.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useCopySnippet } from "@/hooks/useCopyToClipboard" 4 | import CopyButton from "@/components/CopyButton" 5 | import {motion} from 'framer-motion' 6 | 7 | export const AllProductsSnip = () => { 8 | const {snipRef, handleCopy, isCopied} = useCopySnippet() 9 | 10 | return ( 11 |
 12 |         
 13 | {`fetch("https://fakestoreapi.in/api/products")
 14 | .then(res => res.json())
 15 | .then(res => console.log(res))
 16 | `}          
 17 |         
 18 |         
 19 |       
20 | ) 21 | } 22 | export const AllProductsOutputSnip = () => { 23 | 24 | return ( 25 |
26 | 31 |
 32 |         
 33 |       {`
 34 |   {
 35 |   "status": "SUCCESS",
 36 |   "message": "Here you go! You've received...",
 37 |   "products": [
 38 |   {
 39 |     id: 1,
 40 |     title: "Sony WH-1000XM3...",
 41 |     image: "https://storage...",
 42 |     price: 773,
 43 |     description: "Industry leading Active Noise...",
 44 |     brand: "sony",
 45 |     model: "WH-1000XM3",
 46 |     color: "silver",
 47 |     category: "audio",
 48 |     discount: 11
 49 |   },
 50 |   {
 51 |     id: 2,
 52 |     title: "Microsoft Xbox...",
 53 |     image: "https://storage...",
 54 |     price: 57,
 55 |     description: "Experience the modernized design of the Xbox...",
 56 |     brand: "microsoft",
 57 |     model: "Xbox X/S",
 58 |     color: "white",
 59 |     category: "gaming",
 60 |     popular: true,
 61 |     discount: 4
 62 |   },
 63 |   // {...},
 64 |   {
 65 |     id: 149,
 66 |     title: 'Security Camera, IP67 Waterproof...',
 67 |     image: 'https://storage...',
 68 |     price: 737,
 69 |     description: 'Microwave induction is an active...',
 70 |     brand: "Wuqioei",
 71 |     model: "YN50",
 72 |     color: "black+white",
 73 |     category: "appliances",
 74 |     onSale: true,
 75 |     discount: 23
 76 |     }
 77 |    ]
 78 |   }
 79 |       `}
 80 |         
 81 |       
82 |
83 | ) 84 | } 85 | export const SingleProductSnip = () => { 86 | const {snipRef, handleCopy, isCopied} = useCopySnippet() 87 | 88 | return ( 89 |
 90 |         
 91 |  {`fetch("https://fakestoreapi.in/api/products/2") 
 92 | .then(res => res.json())
 93 | .then(res => console.log(res))
 94 | `}          
 95 |         
 96 |         
 97 |       
98 | ) 99 | } 100 | export const SingleProductOutputSnip = () => { 101 | 102 | return ( 103 |
104 | 109 |
110 |         
111 |       {`
112 |  {
113 |   "status": "SUCCESS",
114 |   "message": "Here you've a single product requested for id 2",
115 |   "product": {
116 |     "id": 2,
117 |     "title": "Microsoft Xbox X/S Wireless...",
118 |     "image": "https://storage...",
119 |     "price": 57,
120 |     "description": "Experience the modernized design...",
121 |     "brand": "microsoft",
122 |     "model": "Xbox X/S",
123 |     "color": "white",
124 |     "category": "gaming",
125 |     "popular": true,
126 |     "discount": 4
127 |   }
128 | }
129 |       `}
130 |         
131 |       
132 |
133 | ) 134 | } 135 | export const LimitedProductSnip = () => { 136 | const {snipRef, handleCopy, isCopied} = useCopySnippet() 137 | 138 | return ( 139 |
140 |         
141 |  {`fetch("https://fakestoreapi.in/api/products?limit=2") 
142 | .then(res => res.json())
143 | .then(res => console.log(res))
144 | `}          
145 |         
146 |         
147 |       
148 | ) 149 | } 150 | export const LimitedProductOutputSnip = () => { 151 | 152 | return ( 153 |
154 | 159 |
160 |         
161 |       {`
162 |    {
163 |     "status": "SUCCESS",
164 |     "message": "Here you go! You've received 2...",
165 |     "products": [
166 |       {
167 |         "id": 1,
168 |         "title": "Sony WH-1000XM3 Bluetooth...",
169 |         "image": "https://storage...",
170 |         "price": 773,
171 |         "description": "Digital noise cancelling...",
172 |         "brand": "sony",
173 |         "model": "WH-1000XM3",
174 |         "color": "silver",
175 |         "category": "audio",
176 |         "discount": 11
177 |       },
178 |       {
179 |         "id": 2,
180 |         "title": "Microsoft Xbox X/S Wireless...",
181 |         "image": "https://storage...",
182 |         "price": 57,
183 |         "description": "Experience the modernized...",
184 |         "brand": "microsoft",
185 |         "model": "Xbox X/S",
186 |         "color": "white",
187 |         "category": "gaming",
188 |         "popular": true,
189 |         "discount": 4
190 |       }
191 |     ]
192 |   }
193 |       `}
194 |         
195 |       
196 |
197 | ) 198 | } 199 | export const PaginationSnip = () => { 200 | const {snipRef, handleCopy, isCopied} = useCopySnippet() 201 | 202 | return ( 203 | <>
204 |         
205 |  {`fetch("https://fakestoreapi.in/api/products?page=2")
206 | .then(res => res.json())
207 | .then(res => console.log(res))
208 | `}          
209 |         
210 |         
211 |       
212 |
213 |

214 | ⚡ By default, we send 50 products. use{" "} 215 | 216 | /products?page=2&limit=20 217 | {" "} 218 | to limit products per page. 219 |

220 |

221 | 💁‍♂️ You don't need to pass{" "} 222 | 223 | ?skip=20 224 | {" "} 225 | query, we took care of that. 226 |

227 |
228 | 229 | ) 230 | } 231 | export const PaginationOutputSnip = () => { 232 | 233 | return ( 234 |
235 | 240 |
241 |         
242 |       {`
243 |   {
244 |     "status": "SUCCESS",
245 |     "message": "Here you go! You've received 50...",
246 |     "products": [    
247 |   {
248 |     "id": 51,
249 |     "title": " Samsung  4K Ultra ...",
250 |     "image": "https://storage...",
251 |     "price": 2016,
252 |     "description": "Resolution: 4K Ultra HD (3840x2160)...",
253 |     "brand": "samsung",
254 |     "model": "QA55Q80RAKXXL",
255 |     "color": "black",
256 |     "category": "tv",
257 |     "onSale": true,
258 |     "discount": 19
259 |   }, 
260 |   // {...},   
261 |   {
262 |     "id": 100,
263 |     "title": "Logitech G PRO X Gaming...",
264 |     "image": "https://storage...",
265 |     "price": 336,
266 |     "description": "Blue VO!CE microphone technology*...",
267 |     "brand": "Logitech G",
268 |     "model": "G PRO X",
269 |     "color": "black",
270 |     "category": "gaming",
271 |     "discount": 9
272 |   }
273 |  ]
274 | }
275 |       `}
276 |         
277 |       
278 |
279 | ) 280 | } 281 | export const ProductsCategorySnip = () => { 282 | const {snipRef, handleCopy, isCopied} = useCopySnippet() 283 | 284 | return ( 285 |
286 |         
287 |  {`fetch("https://fakestoreapi.in/api/products/category")
288 | .then(res => res.json())
289 | .then(res => console.log(res))
290 | `}          
291 |         
292 |         
293 |       
294 | ) 295 | } 296 | export const ProductsCategoryOutputSnip = () => { 297 | 298 | return ( 299 |
300 | 305 |
306 |         
307 |       {`
308 |  {
309 |   "status": "SUCCESS",
310 |   "message": "We have 6 categories to choose from.",
311 |   "categories": [
312 |     "tv",
313 |     "audio",
314 |     "laptop",
315 |     "mobile",
316 |     "gaming",
317 |     "appliances"
318 |   ]
319 | }
320 |       `}
321 |         
322 |       
323 |
324 | ) 325 | } 326 | export const ProductsofCategorySnip = () => { 327 | const {snipRef, handleCopy, isCopied} = useCopySnippet() 328 | 329 | return ( 330 |
331 |         
332 |  {`fetch("https://fakestoreapi.in/api/products/category?type=mobile")
333 | .then(res => res.json())
334 | .then(res => console.log(res))
335 | `}          
336 |         
337 |         
338 |       
339 | ) 340 | } 341 | export const ProductsofCategoryOutputSnip = () => { 342 | 343 | return ( 344 |
345 | 350 |
351 |         
352 |       {`
353 |  {
354 |   "status": "SUCCESS",
355 |   "message": "You've received products from the mobile category only.",
356 |   "products": [
357 |     {
358 |       "id": 8,
359 |       "title": "Samsung Galaxy S21 FE 5G...",
360 |       "image": "https://storage...",
361 |       "price": 434,
362 |       "description": "Pro-grade Camera with AI Single Take...",
363 |       "brand": "samsung",
364 |       "model": "Samsung Galaxy S21 FE 5G ...",
365 |       "color": "Lavender",
366 |       "category": "mobile",
367 |       "discount": 9,
368 |       "onSale": true
369 |     },
370 |     {
371 |       "id": 10,
372 |       "title": "Samsung Galaxy S22 5G...",
373 |       "image": "https://storage...",
374 |       "price": 760,
375 |       "description": "Pro-grade Camera that lets...",
376 |       "brand": "samsung",
377 |       "model": "Samsung Galaxy S22 5G",
378 |       "color": "White",
379 |       "category": "mobile",
380 |       "discount": 29
381 |     },
382 |   ]
383 | }
384 |       `}
385 |         
386 |       
387 |
388 | ) 389 | } 390 | export const AddProductSnip = () => { 391 | const {snipRef, handleCopy, isCopied} = useCopySnippet() 392 | 393 | return ( 394 |
395 |         
396 |  {`fetch("https://fakestoreapi.in/api/products", {
397 |   method: 'POST',
398 |   headers: { 'Content-Type': 'application/json' },
399 |   body: JSON.stringify({
400 |     title: "Apple Vision Pro",
401 |     brand: "Apple",
402 |     model: "Apple vision pro First Gen",
403 |      color: "Black",
404 |     category: "appliances",
405 |     discount: 1
406 |   })
407 | })
408 | `}          
409 |         
410 |         
411 |       
412 | ) 413 | } 414 | export const AddProductOutputSnip = () => { 415 | 416 | return ( 417 |
418 | 423 |
424 |         
425 |       {`
426 |  {
427 |   "status": "SUCCESS",
428 |   "message": "Here is the product you sent,...",
429 |   "product": {
430 |     "id": 150,
431 |     "title": "Apple Vision Pro",
432 |     "brand": "Apple",
433 |     "model": "Apple vision pro First Gen",
434 |     "color": "Black",
435 |     "category": "appliances",
436 |     "discount": 1
437 |   }
438 | }
439 |       `}
440 |         
441 |       
442 |
443 | ) 444 | } 445 | export const UpdateProductSnip = () => { 446 | const {snipRef, handleCopy, isCopied} = useCopySnippet() 447 | 448 | return ( 449 |
450 |         
451 |  {`fetch("https://fakestoreapi.in/api/products/2", {
452 |   method: 'PUT',
453 |   headers: { 'Content-Type': 'application/json' },
454 |   body: JSON.stringify({
455 |     model: "Apple vision pro Second Gen",
456 |     color: "Blue",
457 |     discount: 47
458 |   })
459 | })
460 | `}          
461 |         
462 |         
463 |       
464 | ) 465 | } 466 | export const UpdateProductOutputSnip = () => { 467 | 468 | return ( 469 |
470 | 475 |
476 |         
477 |       {`
478 |  {
479 |   "status": "SUCCESS",
480 |   "message": "The product with id 2 has been replaced with your provided data",
481 |   "product": {
482 |     "id": "2",
483 |     "title": "Apple Vision Pro",
484 |     "brand": "Apple",
485 |     "model": "Apple vision pro Second Gen",
486 |     "color": "Blue",
487 |     "category": "appliances",
488 |     "discount": "47"
489 |   }
490 | }
491 |       `}
492 |         
493 |       
494 |
495 | ) 496 | } 497 | export const DeleteProductSnip = () => { 498 | const {snipRef, handleCopy, isCopied} = useCopySnippet() 499 | 500 | return ( 501 |
502 |         
503 |  {`fetch("https://fakestoreapi.in/api/products/2", {
504 |   method: 'DELETE',
505 | }).then(res => res.json())
506 | .then(res => console.log(res))
507 | `}          
508 |         
509 |         
510 |       
511 | ) 512 | } 513 | export const DeleteProductOutputSnip = () => { 514 | 515 | return ( 516 |
517 | 522 |
523 |         
524 |       {`
525 |  {
526 |   "status": "SUCCESS",
527 |   "message": "Product with id 2 has been deleted"
528 | }
529 |       `}
530 |         
531 |       
532 |
533 | ) 534 | } 535 | -------------------------------------------------------------------------------- /public/Illustration.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/api/data/user/users.ts: -------------------------------------------------------------------------------- 1 | export const Users = [ 2 | { 3 | id: 1, 4 | email: 'michael@simpson.com', 5 | username: 'michaelsimpson', 6 | password: '@K(5UejhL&', 7 | name: { 8 | firstname: 'Michael', 9 | lastname: 'Simpson', 10 | }, 11 | address: { 12 | city: 'Joelton', 13 | street: 'Angela Spring', 14 | number: '868', 15 | zipcode: '75070', 16 | geolocation: { 17 | lat: 19.7091875, 18 | long: -14.782061, 19 | }, 20 | }, 21 | phone: '562.548.9768x73853', 22 | }, 23 | { 24 | id: 2, 25 | email: 'april@boyd.com', 26 | username: 'aprilboyd', 27 | password: 'k8WR_hX0+m', 28 | name: { 29 | firstname: 'April', 30 | lastname: 'Boyd', 31 | }, 32 | address: { 33 | city: 'Ericchester', 34 | street: 'Johnson Mountains', 35 | number: '5522', 36 | zipcode: '87835', 37 | geolocation: { 38 | lat: 39.2711365, 39 | long: -56.601702, 40 | }, 41 | }, 42 | phone: '9329508218', 43 | }, 44 | { 45 | id: 3, 46 | email: 'patricia@mullins.com', 47 | username: 'patriciamullins', 48 | password: 'u^M77I7dbM', 49 | name: { 50 | firstname: 'Patricia', 51 | lastname: 'Mullins', 52 | }, 53 | address: { 54 | city: 'Davistown', 55 | street: 'Cooper Lane', 56 | number: '27684', 57 | zipcode: '30806', 58 | geolocation: { 59 | lat: -22.803891, 60 | long: 151.858212, 61 | }, 62 | }, 63 | phone: '9377973776', 64 | }, 65 | { 66 | id: 4, 67 | email: 'kevin@gamble.com', 68 | username: 'kevingamble', 69 | password: '@M4OI#uSdi', 70 | name: { 71 | firstname: 'Kevin', 72 | lastname: 'Gamble', 73 | }, 74 | address: { 75 | city: 'North Stevenberg', 76 | street: 'Kim Shores', 77 | number: '900', 78 | zipcode: '19699', 79 | geolocation: { 80 | lat: -2.1177155, 81 | long: -135.756343, 82 | }, 83 | }, 84 | phone: '904-258-2712x84937', 85 | }, 86 | { 87 | id: 5, 88 | email: 'rhonda@reed.com', 89 | username: 'rhondareed', 90 | password: 'rM%!26Ma*E', 91 | name: { 92 | firstname: 'Rhonda', 93 | lastname: 'Reed', 94 | }, 95 | address: { 96 | city: 'West Paulport', 97 | street: 'Angela Village', 98 | number: '683', 99 | zipcode: '71670', 100 | geolocation: { 101 | lat: 35.166168, 102 | long: -75.177142, 103 | }, 104 | }, 105 | phone: '+1-232-817-5604x09977', 106 | }, 107 | { 108 | id: 6, 109 | email: 'steven@mills.com', 110 | username: 'stevenmills', 111 | password: '_6sweDZm^S', 112 | name: { 113 | firstname: 'Steven', 114 | lastname: 'Mills', 115 | }, 116 | address: { 117 | city: 'Michaelland', 118 | street: 'Snyder Hills', 119 | number: '38589', 120 | zipcode: '64908', 121 | geolocation: { 122 | lat: -17.072697, 123 | long: 32.991439, 124 | }, 125 | }, 126 | phone: '+1-702-709-9757', 127 | }, 128 | { 129 | id: 7, 130 | email: 'tracy@frey.com', 131 | username: 'tracyfrey', 132 | password: '#y5ITp+_(C', 133 | name: { 134 | firstname: 'Tracy', 135 | lastname: 'Frey', 136 | }, 137 | address: { 138 | city: 'East Mary', 139 | street: 'Tracey Trace', 140 | number: '107', 141 | zipcode: '16482', 142 | geolocation: { 143 | lat: -0.870534, 144 | long: -98.235893, 145 | }, 146 | }, 147 | phone: '493.409.0584', 148 | }, 149 | { 150 | id: 8, 151 | email: 'michaela@alvarez.com', 152 | username: 'michaelaalvarez', 153 | password: 'azgP5vDv#j', 154 | name: { 155 | firstname: 'Michaela', 156 | lastname: 'Alvarez', 157 | }, 158 | address: { 159 | city: 'Riveraside', 160 | street: 'Jones Park', 161 | number: '755', 162 | zipcode: '71355', 163 | geolocation: { 164 | lat: 66.7886535, 165 | long: -154.668742, 166 | }, 167 | }, 168 | phone: '(229)313-5846x42107', 169 | }, 170 | { 171 | id: 9, 172 | email: 'mark@rowe.com', 173 | username: 'markrowe', 174 | password: '^b1)#W3jw*', 175 | name: { 176 | firstname: 'Mark', 177 | lastname: 'Rowe', 178 | }, 179 | address: { 180 | city: 'Garyburgh', 181 | street: 'Scott Mall', 182 | number: '6923', 183 | zipcode: '47177', 184 | geolocation: { 185 | lat: 13.2681375, 186 | long: 127.471192, 187 | }, 188 | }, 189 | phone: '369-747-1527x873', 190 | }, 191 | { 192 | id: 10, 193 | email: 'brooke@gibson.com', 194 | username: 'brookegibson', 195 | password: '^!VeDp@5(6', 196 | name: { 197 | firstname: 'Brooke', 198 | lastname: 'Gibson', 199 | }, 200 | address: { 201 | city: 'New Amandaville', 202 | street: 'Alicia Walk', 203 | number: '05944', 204 | zipcode: '09316', 205 | geolocation: { 206 | lat: 68.0450945, 207 | long: 126.116229, 208 | }, 209 | }, 210 | phone: '(424)620-6754x888', 211 | }, 212 | { 213 | id: 11, 214 | email: 'angela@may.com', 215 | username: 'angelamay', 216 | password: '+bC0kv)uv8', 217 | name: { 218 | firstname: 'Angela', 219 | lastname: 'May', 220 | }, 221 | address: { 222 | city: 'New Davidton', 223 | street: 'Diane Squares', 224 | number: '08637', 225 | zipcode: '80044', 226 | geolocation: { 227 | lat: 67.180365, 228 | long: -154.944358, 229 | }, 230 | }, 231 | phone: '(584)218-4823', 232 | }, 233 | { 234 | id: 12, 235 | email: 'john@brown.com', 236 | username: 'johnbrown', 237 | password: 'KD)K2SCdH4', 238 | name: { 239 | firstname: 'John', 240 | lastname: 'Brown', 241 | }, 242 | address: { 243 | city: 'Lawsonborough', 244 | street: 'Bishop Glens', 245 | number: '5771', 246 | zipcode: '45275', 247 | geolocation: { 248 | lat: -45.902952, 249 | long: 92.839473, 250 | }, 251 | }, 252 | phone: '001-638-449-9490x69483', 253 | }, 254 | { 255 | id: 13, 256 | email: 'evan@harris.com', 257 | username: 'evanharris', 258 | password: '_A94LE6fcr', 259 | name: { 260 | firstname: 'Evan', 261 | lastname: 'Harris', 262 | }, 263 | address: { 264 | city: 'North Sheila', 265 | street: 'Clarence Row', 266 | number: '1329', 267 | zipcode: '98096', 268 | geolocation: { 269 | lat: -12.0549555, 270 | long: -156.569036, 271 | }, 272 | }, 273 | phone: '9317021219', 274 | }, 275 | { 276 | id: 14, 277 | email: 'shannon@pearson.com', 278 | username: 'shannonpearson', 279 | password: 'At5$Phgu(o', 280 | name: { 281 | firstname: 'Shannon', 282 | lastname: 'Pearson', 283 | }, 284 | address: { 285 | city: 'New Jacquelinefurt', 286 | street: 'Sarah Extensions', 287 | number: '5475', 288 | zipcode: '16642', 289 | geolocation: { 290 | lat: 7.1229115, 291 | long: -27.069586, 292 | }, 293 | }, 294 | phone: '001-979-338-3931', 295 | }, 296 | { 297 | id: 15, 298 | email: 'david@myers.com', 299 | username: 'davidmyers', 300 | password: 'Y37pjSts&J', 301 | name: { 302 | firstname: 'David', 303 | lastname: 'Myers', 304 | }, 305 | address: { 306 | city: 'Lake Pamela', 307 | street: 'Tiffany Plain', 308 | number: '625', 309 | zipcode: '73260', 310 | geolocation: { 311 | lat: 45.581179, 312 | long: -2.087226, 313 | }, 314 | }, 315 | phone: '960-790-1079x3821', 316 | }, 317 | { 318 | id: 16, 319 | email: 'christopher@abbott.com', 320 | username: 'christopherabbott', 321 | password: 'jzJE9)i0@2', 322 | name: { 323 | firstname: 'Christopher', 324 | lastname: 'Abbott', 325 | }, 326 | address: { 327 | city: 'North Aaronstad', 328 | street: 'Williams Spur', 329 | number: '60921', 330 | zipcode: '28227', 331 | geolocation: { 332 | lat: -73.2773035, 333 | long: 98.871484, 334 | }, 335 | }, 336 | phone: '200-404-0063', 337 | }, 338 | { 339 | id: 17, 340 | email: 'bradley@oneill.com', 341 | username: 'bradleyoneill', 342 | password: '%m7*EMjN!o', 343 | name: { 344 | firstname: 'Bradley', 345 | lastname: 'Oneill', 346 | }, 347 | address: { 348 | city: 'Collinsfurt', 349 | street: 'Gary Mission', 350 | number: '168', 351 | zipcode: '37670', 352 | geolocation: { 353 | lat: 89.1496435, 354 | long: -39.222774, 355 | }, 356 | }, 357 | phone: '001-966-538-2213', 358 | }, 359 | { 360 | id: 18, 361 | email: 'brandi@herrera.com', 362 | username: 'brandiherrera', 363 | password: 'N%M6RrYsA*', 364 | name: { 365 | firstname: 'Brandi', 366 | lastname: 'Herrera', 367 | }, 368 | address: { 369 | city: 'North Russellstad', 370 | street: 'Montoya Village', 371 | number: '4554', 372 | zipcode: '01691', 373 | geolocation: { 374 | lat: 41.795336, 375 | long: -25.061192, 376 | }, 377 | }, 378 | phone: '2082615578', 379 | }, 380 | { 381 | id: 19, 382 | email: 'peter@colon.com', 383 | username: 'petercolon', 384 | password: '1&oHooMg!y', 385 | name: { 386 | firstname: 'Peter', 387 | lastname: 'Colon', 388 | }, 389 | address: { 390 | city: 'South Parker', 391 | street: 'Steven Mountain', 392 | number: '414', 393 | zipcode: '15230', 394 | geolocation: { 395 | lat: 58.4038645, 396 | long: 116.052145, 397 | }, 398 | }, 399 | phone: '001-616-562-6818x6964', 400 | }, 401 | { 402 | id: 20, 403 | email: 'timothy@burton.com', 404 | username: 'timothyburton', 405 | password: '&$)QeGpZ25', 406 | name: { 407 | firstname: 'Timothy', 408 | lastname: 'Burton', 409 | }, 410 | address: { 411 | city: 'Lake Tara', 412 | street: 'Christopher Mall', 413 | number: '03542', 414 | zipcode: '30914', 415 | geolocation: { 416 | lat: -38.3088175, 417 | long: -143.125308, 418 | }, 419 | }, 420 | phone: '+1-293-912-5353x125', 421 | }, 422 | { 423 | id: 21, 424 | email: 'destiny@powers.com', 425 | username: 'destinypowers', 426 | password: 'h6I6La6H2(', 427 | name: { 428 | firstname: 'Destiny', 429 | lastname: 'Powers', 430 | }, 431 | address: { 432 | city: 'East Joseph', 433 | street: 'Kathleen Ferry', 434 | number: '4246', 435 | zipcode: '46095', 436 | geolocation: { 437 | lat: -3.1928205, 438 | long: -94.768723, 439 | }, 440 | }, 441 | phone: '(725)466-6824', 442 | }, 443 | { 444 | id: 22, 445 | email: 'holly@smith.com', 446 | username: 'hollysmith', 447 | password: '+3^ZDgm0Zy', 448 | name: { 449 | firstname: 'Holly', 450 | lastname: 'Smith', 451 | }, 452 | address: { 453 | city: 'North Rebeccaburgh', 454 | street: 'Preston Plains', 455 | number: '8742', 456 | zipcode: '94639', 457 | geolocation: { 458 | lat: -43.2724925, 459 | long: 47.442729, 460 | }, 461 | }, 462 | phone: '601-356-0295x93782', 463 | }, 464 | { 465 | id: 23, 466 | email: 'mark@fuller.com', 467 | username: 'markfuller', 468 | password: 'OAu(4ZSvX(', 469 | name: { 470 | firstname: 'Mark', 471 | lastname: 'Fuller', 472 | }, 473 | address: { 474 | city: 'Port Anthony', 475 | street: 'Robinson Terrace', 476 | number: '0604', 477 | zipcode: '43675', 478 | geolocation: { 479 | lat: 21.1919605, 480 | long: 175.242688, 481 | }, 482 | }, 483 | phone: '551-599-1718x798', 484 | }, 485 | { 486 | id: 24, 487 | email: 'chelsey@lambert.com', 488 | username: 'chelseylambert', 489 | password: 'SVv*5Wieb3', 490 | name: { 491 | firstname: 'Chelsey', 492 | lastname: 'Lambert', 493 | }, 494 | address: { 495 | city: 'Lake Fredericktown', 496 | street: 'Allison Locks', 497 | number: '338', 498 | zipcode: '18143', 499 | geolocation: { 500 | lat: 33.773501, 501 | long: -150.074023, 502 | }, 503 | }, 504 | phone: '407-901-1793', 505 | }, 506 | { 507 | id: 25, 508 | email: 'jamie@hughes.com', 509 | username: 'jamiehughes', 510 | password: '%W@5SXiVA(', 511 | name: { 512 | firstname: 'Jamie', 513 | lastname: 'Hughes', 514 | }, 515 | address: { 516 | city: 'Markstad', 517 | street: 'Susan Centers', 518 | number: '024', 519 | zipcode: '70566', 520 | geolocation: { 521 | lat: 12.756613, 522 | long: 100.099164, 523 | }, 524 | }, 525 | phone: '6444222632', 526 | }, 527 | { 528 | id: 26, 529 | email: 'james@barnes.com', 530 | username: 'jamesbarnes', 531 | password: 'ucPm+A8c%7', 532 | name: { 533 | firstname: 'James', 534 | lastname: 'Barnes', 535 | }, 536 | address: { 537 | city: 'North Toddchester', 538 | street: 'Cole Terrace', 539 | number: '464', 540 | zipcode: '32265', 541 | geolocation: { 542 | lat: 50.072941, 543 | long: 144.509923, 544 | }, 545 | }, 546 | phone: '(397)657-8974', 547 | }, 548 | { 549 | id: 27, 550 | email: 'david@lawrence.com', 551 | username: 'davidlawrence', 552 | password: '(3xGOR^SBy', 553 | name: { 554 | firstname: 'David', 555 | lastname: 'Lawrence', 556 | }, 557 | address: { 558 | city: 'Martinview', 559 | street: 'Smith Island', 560 | number: '235', 561 | zipcode: '56780', 562 | geolocation: { 563 | lat: -46.3209955, 564 | long: -158.040183, 565 | }, 566 | }, 567 | phone: '6885587925', 568 | }, 569 | { 570 | id: 28, 571 | email: 'kathy@fischer.com', 572 | username: 'kathyfischer', 573 | password: '+Qe9T*vzV5', 574 | name: { 575 | firstname: 'Kathy', 576 | lastname: 'Fischer', 577 | }, 578 | address: { 579 | city: 'New Beverly', 580 | street: 'Sims Loop', 581 | number: '0729', 582 | zipcode: '04021', 583 | geolocation: { 584 | lat: 59.8887915, 585 | long: -120.896784, 586 | }, 587 | }, 588 | phone: '001-468-443-1072x3335', 589 | }, 590 | { 591 | id: 29, 592 | email: 'katrina@coleman.com', 593 | username: 'katrinacoleman', 594 | password: '+1!BJzxzTo', 595 | name: { 596 | firstname: 'Katrina', 597 | lastname: 'Coleman', 598 | }, 599 | address: { 600 | city: 'New Charles', 601 | street: 'Robert Court', 602 | number: '4965', 603 | zipcode: '16837', 604 | geolocation: { 605 | lat: -9.338257, 606 | long: 23.822567, 607 | }, 608 | }, 609 | phone: '573-419-3667', 610 | }, 611 | { 612 | id: 30, 613 | email: 'beth@matthews.com', 614 | username: 'bethmatthews', 615 | password: '_ZR1FhibNp', 616 | name: { 617 | firstname: 'Beth', 618 | lastname: 'Matthews', 619 | }, 620 | address: { 621 | city: 'New Brianna', 622 | street: 'David River', 623 | number: '617', 624 | zipcode: '02657', 625 | geolocation: { 626 | lat: -3.926369, 627 | long: -34.155067, 628 | }, 629 | }, 630 | phone: '701.940.9818x9554', 631 | }, 632 | { 633 | id: 31, 634 | email: 'cassandra@davis.com', 635 | username: 'cassandradavis', 636 | password: ')Q6QSRDvFT', 637 | name: { 638 | firstname: 'Cassandra', 639 | lastname: 'Davis', 640 | }, 641 | address: { 642 | city: 'Jamieport', 643 | street: 'Lewis Cove', 644 | number: '2712', 645 | zipcode: '97876', 646 | geolocation: { 647 | lat: -5.763115, 648 | long: 167.118573, 649 | }, 650 | }, 651 | phone: '849.342.1166x82464', 652 | }, 653 | { 654 | id: 32, 655 | email: 'dennis@anderson.com', 656 | username: 'dennisanderson', 657 | password: '*t3ng9LmTO', 658 | name: { 659 | firstname: 'Dennis', 660 | lastname: 'Anderson', 661 | }, 662 | address: { 663 | city: 'Gravesfort', 664 | street: 'David Wall', 665 | number: '2553', 666 | zipcode: '28211', 667 | geolocation: { 668 | lat: -71.5690115, 669 | long: -108.717582, 670 | }, 671 | }, 672 | phone: '731-284-1928x997', 673 | }, 674 | { 675 | id: 33, 676 | email: 'nicholas@meza.com', 677 | username: 'nicholasmeza', 678 | password: 'dXB7NMf3&+', 679 | name: { 680 | firstname: 'Nicholas', 681 | lastname: 'Meza', 682 | }, 683 | address: { 684 | city: 'Morabury', 685 | street: 'Reyes Junctions', 686 | number: '3301', 687 | zipcode: '12897', 688 | geolocation: { 689 | lat: -61.8404755, 690 | long: 45.385139, 691 | }, 692 | }, 693 | phone: '2842447276', 694 | }, 695 | { 696 | id: 34, 697 | email: 'dorothy@english.com', 698 | username: 'dorothyenglish', 699 | password: '$3yZbVRorC', 700 | name: { 701 | firstname: 'Dorothy', 702 | lastname: 'English', 703 | }, 704 | address: { 705 | city: 'Port Angela', 706 | street: 'Miller Lights', 707 | number: '24091', 708 | zipcode: '43889', 709 | geolocation: { 710 | lat: -22.623968, 711 | long: 138.769011, 712 | }, 713 | }, 714 | phone: '326.620.3150x4460', 715 | }, 716 | { 717 | id: 35, 718 | email: 'jose@wright.com', 719 | username: 'josewright', 720 | password: '0!W0WKioqX', 721 | name: { 722 | firstname: 'Jose', 723 | lastname: 'Wright', 724 | }, 725 | address: { 726 | city: 'West Markberg', 727 | street: 'Cohen Grove', 728 | number: '53726', 729 | zipcode: '83974', 730 | geolocation: { 731 | lat: 80.9201245, 732 | long: -24.898629, 733 | }, 734 | }, 735 | phone: '5066866779', 736 | }, 737 | { 738 | id: 36, 739 | email: 'james@williams.com', 740 | username: 'jameswilliams', 741 | password: 'Q%91Cybuh_', 742 | name: { 743 | firstname: 'James', 744 | lastname: 'Williams', 745 | }, 746 | address: { 747 | city: 'South Aaronside', 748 | street: 'Laurie Plain', 749 | number: '80284', 750 | zipcode: '40864', 751 | geolocation: { 752 | lat: -61.432408, 753 | long: 24.749421, 754 | }, 755 | }, 756 | phone: '848.273.1969', 757 | }, 758 | { 759 | id: 37, 760 | email: 'anne@martin.com', 761 | username: 'annemartin', 762 | password: 'j!p4F3wKXJ', 763 | name: { 764 | firstname: 'Anne', 765 | lastname: 'Martin', 766 | }, 767 | address: { 768 | city: 'South Tonystad', 769 | street: 'Anthony Glens', 770 | number: '6590', 771 | zipcode: '40813', 772 | geolocation: { 773 | lat: 69.916301, 774 | long: -55.154016, 775 | }, 776 | }, 777 | phone: '001-327-914-2909x708', 778 | }, 779 | { 780 | id: 38, 781 | email: 'courtney@hunt.com', 782 | username: 'courtneyhunt', 783 | password: '^@5UNYgpj3', 784 | name: { 785 | firstname: 'Courtney', 786 | lastname: 'Hunt', 787 | }, 788 | address: { 789 | city: 'New Melissaview', 790 | street: 'Oscar Shore', 791 | number: '65269', 792 | zipcode: '60490', 793 | geolocation: { 794 | lat: -47.215432, 795 | long: 49.733035, 796 | }, 797 | }, 798 | phone: '001-670-805-8419x659', 799 | }, 800 | { 801 | id: 39, 802 | email: 'scott@smith.com', 803 | username: 'scottsmith', 804 | password: ')$k2JEgj3P', 805 | name: { 806 | firstname: 'Scott', 807 | lastname: 'Smith', 808 | }, 809 | address: { 810 | city: 'West Jayport', 811 | street: 'Hernandez Vista', 812 | number: '3417', 813 | zipcode: '15091', 814 | geolocation: { 815 | lat: -73.3968265, 816 | long: -158.357588, 817 | }, 818 | }, 819 | phone: '(374)280-6705x0156', 820 | }, 821 | { 822 | id: 40, 823 | email: 'lisa@underwood.com', 824 | username: 'lisaunderwood', 825 | password: 'Lt7R*0Go^@', 826 | name: { 827 | firstname: 'Lisa', 828 | lastname: 'Underwood', 829 | }, 830 | address: { 831 | city: 'Kingtown', 832 | street: 'Hawkins Parkway', 833 | number: '0985', 834 | zipcode: '72734', 835 | geolocation: { 836 | lat: 36.3941675, 837 | long: -165.140526, 838 | }, 839 | }, 840 | phone: '(392)603-8492', 841 | }, 842 | { 843 | id: 41, 844 | email: 'sherry@bird.com', 845 | username: 'sherrybird', 846 | password: '4yl7URZ*(&', 847 | name: { 848 | firstname: 'Sherry', 849 | lastname: 'Bird', 850 | }, 851 | address: { 852 | city: 'Port Kylie', 853 | street: 'Edward Ferry', 854 | number: '8774', 855 | zipcode: '52044', 856 | geolocation: { 857 | lat: -59.1552815, 858 | long: 111.265657, 859 | }, 860 | }, 861 | phone: '7153701233', 862 | }, 863 | { 864 | id: 42, 865 | email: 'nicholas@hart.com', 866 | username: 'nicholashart', 867 | password: '*2Hv7H*_^t', 868 | name: { 869 | firstname: 'Nicholas', 870 | lastname: 'Hart', 871 | }, 872 | address: { 873 | city: 'Robertview', 874 | street: 'Todd Port', 875 | number: '876', 876 | zipcode: '68990', 877 | geolocation: { 878 | lat: -76.0809775, 879 | long: -76.60808, 880 | }, 881 | }, 882 | phone: '882-707-7101', 883 | }, 884 | { 885 | id: 43, 886 | email: 'christine@fox.com', 887 | username: 'christinefox', 888 | password: '!jjtH$&ii4', 889 | name: { 890 | firstname: 'Christine', 891 | lastname: 'Fox', 892 | }, 893 | address: { 894 | city: 'Port Lindaburgh', 895 | street: 'Larsen Place', 896 | number: '033', 897 | zipcode: '86378', 898 | geolocation: { 899 | lat: -51.6462635, 900 | long: -119.590189, 901 | }, 902 | }, 903 | phone: '(470)995-3954x876', 904 | }, 905 | { 906 | id: 44, 907 | email: 'kelly@black.com', 908 | username: 'kellyblack', 909 | password: 'LARWQe)p^9', 910 | name: { 911 | firstname: 'Kelly', 912 | lastname: 'Black', 913 | }, 914 | address: { 915 | city: 'Whiteborough', 916 | street: 'Heather Branch', 917 | number: '89454', 918 | zipcode: '21772', 919 | geolocation: { 920 | lat: -13.31858, 921 | long: 134.583367, 922 | }, 923 | }, 924 | phone: '835-853-4994x02336', 925 | }, 926 | { 927 | id: 45, 928 | email: 'jennifer@white.com', 929 | username: 'jenniferwhite', 930 | password: '1u$4Lubs(2', 931 | name: { 932 | firstname: 'Jennifer', 933 | lastname: 'White', 934 | }, 935 | address: { 936 | city: 'West Sherry', 937 | street: 'Charles Fork', 938 | number: '267', 939 | zipcode: '03615', 940 | geolocation: { 941 | lat: 4.645282, 942 | long: 108.529783, 943 | }, 944 | }, 945 | phone: '+1-749-588-1148x00215', 946 | }, 947 | { 948 | id: 46, 949 | email: 'cynthia@walker.com', 950 | username: 'cynthiawalker', 951 | password: 'E^oLi6Gn0n', 952 | name: { 953 | firstname: 'Cynthia', 954 | lastname: 'Walker', 955 | }, 956 | address: { 957 | city: 'Lake Sethshire', 958 | street: 'Andrew Pines', 959 | number: '42795', 960 | zipcode: '26376', 961 | geolocation: { 962 | lat: 21.807033, 963 | long: 34.539396, 964 | }, 965 | }, 966 | phone: '+1-631-724-2202', 967 | }, 968 | { 969 | id: 47, 970 | email: 'timothy@butler.com', 971 | username: 'timothybutler', 972 | password: '%10NL_ihu7', 973 | name: { 974 | firstname: 'Timothy', 975 | lastname: 'Butler', 976 | }, 977 | address: { 978 | city: 'Port Lindamouth', 979 | street: 'Conway Circle', 980 | number: '77899', 981 | zipcode: '46603', 982 | geolocation: { 983 | lat: -43.789039, 984 | long: 128.243191, 985 | }, 986 | }, 987 | phone: '283.515.6203x934', 988 | }, 989 | { 990 | id: 48, 991 | email: 'mary@smith.com', 992 | username: 'marysmith', 993 | password: 'n9FzJlnL_3', 994 | name: { 995 | firstname: 'Mary', 996 | lastname: 'Smith', 997 | }, 998 | address: { 999 | city: 'Mooreport', 1000 | street: 'Church Estate', 1001 | number: '8666', 1002 | zipcode: '96257', 1003 | geolocation: { 1004 | lat: 54.3262735, 1005 | long: 152.795247, 1006 | }, 1007 | }, 1008 | phone: '719-945-7837x41842', 1009 | }, 1010 | { 1011 | id: 49, 1012 | email: 'james@jacobs.com', 1013 | username: 'jamesjacobs', 1014 | password: 'Jg37%VenW@', 1015 | name: { 1016 | firstname: 'James', 1017 | lastname: 'Jacobs', 1018 | }, 1019 | address: { 1020 | city: 'Port Elizabethfort', 1021 | street: 'Jennifer Estates', 1022 | number: '872', 1023 | zipcode: '70240', 1024 | geolocation: { 1025 | lat: 85.0941535, 1026 | long: -83.719686, 1027 | }, 1028 | }, 1029 | phone: '497-368-5013x02578', 1030 | }, 1031 | { 1032 | id: 50, 1033 | email: 'marissa@jefferson.com', 1034 | username: 'marissajefferson', 1035 | password: '&0DRqNTClm', 1036 | name: { 1037 | firstname: 'Marissa', 1038 | lastname: 'Jefferson', 1039 | }, 1040 | address: { 1041 | city: 'Paulmouth', 1042 | street: 'Myers Trace', 1043 | number: '93284', 1044 | zipcode: '52775', 1045 | geolocation: { 1046 | lat: 29.74872, 1047 | long: -19.194908, 1048 | }, 1049 | }, 1050 | phone: '925-431-0474', 1051 | }, 1052 | ] 1053 | --------------------------------------------------------------------------------