Giter Club home page Giter Club logo

digitalhippo's Introduction

DigitalHippo - A Modern Fullstack E-Commerce Marketplace for Digital Products

Built with the Next.js 14 App Router, tRPC, TypeScript, Payload & Tailwind

Project Image

Features

  • 🛠️ Complete marketplace built from scratch in Next.js 14
  • 💻 Beautiful landing page & product pages included
  • 🎨 Custom artwork included
  • 💳 Full admin dashboard
  • 🛍️ Users can purchase and sell their own products
  • 🛒 Locally persisted shopping cart
  • 🔑 Authentication using Payload
  • 🖥️ Learn how to self-host Next.js
  • 🌟 Clean, modern UI using shadcn-ui
  • ✉️ Beautiful emails for signing up and after purchase
  • ✅ Admins can verify products to ensure high quality
  • ⌨️ 100% written in TypeScript
  • 🎁 ...much more

Getting started

To get started with this project, run

  git clone https://github.com/joschan21/digitalhippo.git

and copy the .env.example variables into a separate .env file, fill them out & and that's all you need to get started!

Acknowledgements

  • Payload for making this project possible

License

MIT

digitalhippo's People

Contributors

ahmedbaset avatar elsangedy avatar joschan21 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

digitalhippo's Issues

not really an issue, more recommendation

hi josh,

thanks for this awesome video.. following it I noticed some improvements.. you could use more eslint rules :) for example eslint-config-prettier, eslint-config-standard and eslint-plugin-tailwindcss

eslint-plugin-tailwindcss helps a lot with tailwindcss, since i've noticed that you once used text-medium which doesnt exist but i think you wanted to use font-medium

.eslintrc.json
{ "extends": ["next/core-web-vitals", "standard", "plugin:tailwindcss/recommended", "prettier"] }

cheers

dev script doesn't compile tailwind

hello everyone!

i might be wrong or miss something, but the "npm run dev" script that executes "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts nodemon" only compile the ts file, there's no tailwind hot reload compiler command that needs to be executed. how to improve this script to make it also run a tailwind CSS compiler. or if it needs to be split, then how to do it?

thankss

Unable to Progress ahead due to unable to signin

Video timestamp: 05:10:00

I cant progress ahead deu to when I sign in , It work as I get that toast notification of successful sign and I also get the cookies(jwt token).

But when It takes me to homepage and it doesn't remove the sign in & create account button.

Here is current Navbar.tsx -
Navbar
Here is current payload-util.ts -
payload-util

PrimaryActionEmail Image not provided

Inside the PrimaryActionEmail component there is an image being loaded with the path {${process.env.NEXT_PUBLIC_SERVER_URL}/hippo-newsletter-sign-up.png},
however
there is no such image provided inside the public folder.

login redirect

after adjusting payload in the project I went to payload dashboard it is seen only login page not option on sign-up page or create-first-user but when I type : 3000/sell/create-first-user so my url redirect to login page...
can anyone help me

missing metadata in stripe

hi there,

in order to have metadata available in stripe you need to provide payment_intent_data in the stripeSession

const stripeSession = await stripe.checkout.sessions.create({
  success_url: `${process.env.NEXT_PUBLIC_SERVER_URL}/thank-you?orderId=${order.id}`,
  cancel_url: `${process.env.NEXT_PUBLIC_SERVER_URL}/cart`,
  payment_method_types: ["card", "paypal"],
  mode: "payment",
  metadata: {
    userId: user.id,
    orderId: order.id
  },
  line_items,
  payment_intent_data: {
    metadata: {
      userId: user.id,
      orderId: order.id
    }
  }
});

image

cheers

product images are not visible on webpage

Images of products
Screenshot 2024-04-04 114314
are not visible on webpage

error -> ⨯ The requested resource isn't a valid image for /media/frame.png received text/html; charset=utf-8
⨯ The requested resource isn't a valid image for /media/Designer.png received text/html; charset=utf-8

npm run generate:types error. at 6:21:21.

Hello,

so i am having troubles with running generate:types from json. The code is exactly the same as in the video.

if i run npm run generate:types i get this error :
PS C:\Users\hacke\complete_fullstack_digital_marketplace_app> npm run generate:types

[email protected] generate:types
cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:types

C:\Users\hacke\complete_fullstack_digital_marketplace_app\node_modules\payload\dist\fields\config\sanitize.js:52
throw new _errors.InvalidFieldRelationship(field, relationship);
^

InvalidFieldRelationship: Field Product file(s) has invalid relationship 'product_files'.
at C:\Users\hacke\complete_fullstack_digital_marketplace_app\node_modules\payload\dist\fields\config\sanitize.js:52:31
at Array.forEach ()
at C:\Users\hacke\complete_fullstack_digital_marketplace_app\node_modules\payload\dist\fields\config\sanitize.js:50:31
at Array.map ()
at sanitizeFields (C:\Users\hacke\complete_fullstack_digital_marketplace_app\node_modules\payload\dist\fields\config\sanitize.js:25:19)
at sanitizeCollection (C:\Users\hacke\complete_fullstack_digital_marketplace_app\node_modules\payload\dist\collections\config\sanitize.js:135:53)
at C:\Users\hacke\complete_fullstack_digital_marketplace_app\node_modules\payload\dist\config\sanitize.js:81:85
at Array.map ()
at sanitizeConfig (C:\Users\hacke\complete_fullstack_digital_marketplace_app\node_modules\payload\dist\config\sanitize.js:81:45)
at buildConfig (C:\Users\hacke\complete_fullstack_digital_marketplace_app\node_modules\payload\dist\config\build.js:21:41) {
data: null,
isOperational: true,
isPublic: false,
status: 500
}

Node.js v20.10.0

my ProductFile.ts :

import { User } from "../payload-types";
import { BeforeChangeHook } from "payload/dist/collections/config/types";
import { Access, CollectionConfig } from "payload/types";

const addUser: BeforeChangeHook = ({ req, data }) => {
const user = req.user as User | null
return {...data, user: user?.id}
}

const yourOwnAndPurchased: Access = async ({ req }) => {
const user = req.user as User | null

if( user?.role === "admin" ) return true
if( !user ) return false

const {} = await req.payload.find({
    collection: "products"
})

}

export const ProductFiles: CollectionConfig = {
slug: "product_files",
admin: {
hidden: ({ user }) => user.role !== "admin",
},
hooks: {
beforeChange: [addUser]
},
access: {
read: yourOwnAndPurchased
},
upload: {
staticURL: "/product_files",
staticDir: "product_files",
mimeTypes: ["image/", "font/", "application/postscript"],
},
fields: [
{
name: "user",
type: "relationship",
relationTo: "users",
admin: {
condition: () => false
},
hasMany: false,
required: true,
},
],
}

my payload.config.ts :

import { mongooseAdapter } from "@payloadcms/db-mongodb";
import { slateEditor } from "@payloadcms/richtext-slate";
import { buildConfig } from "payload/config";
import { webpackBundler } from "@payloadcms/bundler-webpack";
import path from "path";
import { Users } from "./collections/Users";
import dotenv from "dotenv";
import { Products } from "./collections/Products/Products";
import { Media } from "./collections/Media";
//IMPORTS************************

dotenv.config({
path: path.resolve(__dirname, "../.env"),
})

export default buildConfig({
serverURL: process.env.NEXT_PUBLIC_SERVER_URL || '',
collections: [Users, Products, Media],
routes: {
admin: '/sell'
},
admin: {
user: "users",
bundler: webpackBundler(),
meta: {
titleSuffix: "- HippoHub",
favicon: "/favicon.ico",
ogImage: "/thumbnail.jpg",
},
},
rateLimit: {
max: 2000,
},
editor: slateEditor({}),
db: mongooseAdapter({
url: process.env.MONGODB_URL!,
}),
typescript: {
outputFile: path.resolve(__dirname, 'payload-types.ts'),
},
})

my Products.ts :

import { PRODUCT_CATEGORIES } from "../../config";
import { CollectionConfig } from "payload/types";

export const Products: CollectionConfig = {
slug: "products",
admin: {
useAsTitle: "name"
},
access: {},
fields: [
{
name: "user",
type: "relationship",
relationTo: "users",
required: true,
hasMany: false,
admin: {
condition: () => false
},
},
{
name: "name",
label: "Name",
type: "text",
required: true,
},
{
name: "description",
type: "textarea",
label: "Product details",
},
{
name: "price",
label: "Price in USD",
min: 0,
max: 1000,
type: "number",
required: true,
},
{
name: "category",
label: "Category",
type: "select",
options: PRODUCT_CATEGORIES.map(({ label, value }) => ({ label, value })
),
required: true,
},
{
name: "product_files",
label: "Product file(s)",
type: "relationship",
required: true,
relationTo: "product_files",
hasMany: false,
},
{
name: "approvedForSale",
label: "Product Status",
type: "select",
defaultValue: "pending",
access: {
create: ({ req }) => req.user.role === "admin",
read: ({ req }) => req.user.role === "admin",
update: ({ req }) => req.user.role === "admin",
},
options: [
{
label: "Pending verification",
value: "pending",
},
{
label: "Approved",
value: "approved",
},
{
label: "Denied",
value: "denied",
},
],
},
{
name: "priceId",
access: {
create: () => false,
read: () => false,
update: () => false,
},
type: "text",
admin: {
hidden: true,
},
},
{
name: "stripeId",
access: {
create: () => false,
read: () => false,
update: () => false,
},
type: "text",
admin: {
hidden: true,
},
},
{
name: "images",
type: "array",
label: "Product images",
minRows: 1,
maxRows: 4,
required: true,
labels: {
singular: "Image",
plural: "Images",
},
fields: [
{
name: "image",
type: "upload",
relationTo: "media",
required: true,
},
],
},
],
}

my package.json :

{
"name": "complete_fullstack_digital_marketplace_app",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts nodemon",
"generate:types": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:types",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@hookform/resolvers": "^3.3.2",
"@payloadcms/bundler-webpack": "^1.0.5",
"@payloadcms/db-mongodb": "^1.0.8",
"@payloadcms/richtext-slate": "^1.2.0",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slot": "^1.0.2",
"@tanstack/react-query": "^4.36.1",
"@trpc/client": "^10.44.1",
"@trpc/next": "^10.44.1",
"@trpc/react-query": "^10.44.1",
"@trpc/server": "^10.44.1",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"cross-env": "^7.0.3",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"lucide-react": "^0.292.0",
"next": "14.0.3",
"nodemailer": "^6.9.7",
"payload": "^2.2.2",
"react": "^18",
"react-dom": "^18",
"react-hook-form": "^7.48.2",
"sonner": "^1.2.4",
"tailwind-merge": "^2.0.0",
"tailwindcss-animate": "^1.0.7",
"zod": "^3.22.4"
},
"devDependencies": {
"@types/express": "^4.17.21",
"@types/node": "^20",
"@types/nodemailer": "^6.4.14",
"@types/react": "^18",
"@types/react-dom": "^18",
"autoprefixer": "^10.0.1",
"eslint": "^8",
"eslint-config-next": "14.0.3",
"nodemon": "^3.0.1",
"postcss": "^8",
"tailwindcss": "^3.3.0",
"typescript": "^5"
}
}

i cant figure this out already spent few days debugging this.

"My Account" drop-down menu not showing after Sign-In

I have to manually refresh the page after sign-in to see the "My Account" drop-down menu in the navigation bar even if I am redirected to the homepage.
In the video, after sign-in, the “My account” drop-down menu appears immediately when redirected to the homepage.

Can you tell me what could be causing this problem? I have tried everything. This is certainly a small detail.

THANKS.

When install payload,There is always a problem about sharp.

The following is a specific error message:
npm ERR! code 1
npm ERR! path E:\sites\digitalhippo2\node_modules\payload\node_modules\sharp
npm ERR! command failed
npm ERR! command C:\WINDOWS\system32\cmd.exe /d /s /c (node install/libvips && node install/dll-copy && prebuild-install) || (node install/can-compile && node-gyp rebuild &&
node install/dll-copy)
npm ERR! sharp: Downloading https://github.com/lovell/sharp-libvips/releases/download/v8.14.5/libvips-8.14.5-win32-x64.tar.br
npm ERR! sharp: Please see https://sharp.pixelplumbing.com/install for required dependencies
npm ERR! sharp: Installation error: connect ETIMEDOUT 20.205.243.166:443

npm ERR! A complete log of this run can be found in: C:\Users\admin\AppData\Local\npm-cache_logs\2024-01-25T12_45_05_689Z-debug-0.log
I took a lot of time for this and wanted to give up

Configure Product file to upload pdf

It really works after deploying. Anyone knows how to configure Product file MIME type so as to upload pdf, besides jpg & png? Thinking of selling ebooks.

TypeError: Response body object should not be disturbed or locked

I have following error at 03:57:55

sign up doesnt work for me, i get 500 internal server error

image

On http://localhost:3000/sell/create-first-user it works, but doesnt work on http://localhost:3000/sign-up

Terminal log:

TypeError: Response body object should not be disturbed or locked

⨯ Error: No response is returned from route handler '\src\app\api\trpc[trpc]\route.ts'. Ensure you return a Response or a NextResponse in all branches of your handler.
at webpack://next/./dist/esm/server/future/route-modules/app-route/module.js:191:35

What can cause the issue?

nextjs doesn't work well with payload now

I have no idea about what happened to nextjs 14, but now it doesn't seem to work with payloads. Maybe you can pull your code and run it and you can get the wrong message like 'ReferenceError: TransformStream is not defined'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.