Project setup, dockerized, prisma schema / migrations setup, component library added

This commit is contained in:
austinkelsay 2023-12-23 17:21:42 -06:00
parent 6b9795f66d
commit 3eaffd8636
13 changed files with 257 additions and 114 deletions

1
.gitignore vendored
View File

@ -5,6 +5,7 @@
/.pnp
.pnp.js
.yarn/install-state.gz
.env
# testing
/coverage

13
Dockerfile Normal file
View File

@ -0,0 +1,13 @@
# syntax=docker/dockerfile:1
FROM node:18.17.0-bullseye
WORKDIR /app
EXPOSE 3000
COPY . .
RUN npm install
CMD ["npm", "run", "dev"]

28
docker-compose.yml Normal file
View File

@ -0,0 +1,28 @@
version: "3"
services:
db:
container_name: plebdevs-db
image: postgres:13.2
restart: always
expose:
- "5432"
ports:
- "5432:5432"
env_file:
- .env
volumes:
- postgres_data:/var/lib/postgresql/data
app:
container_name: plebdevs
build: .
depends_on:
- db
env_file:
- .env
ports:
- "3000:3000"
links:
- db
volumes:
postgres_data:

95
package-lock.json generated
View File

@ -9,6 +9,8 @@
"version": "0.1.0",
"dependencies": {
"next": "14.0.4",
"primeicons": "^6.0.1",
"primereact": "^10.2.1",
"react": "^18",
"react-dom": "^18"
},
@ -30,7 +32,6 @@
"version": "7.23.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.6.tgz",
"integrity": "sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==",
"dev": true,
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
@ -331,6 +332,34 @@
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
"dev": true
},
"node_modules/@types/prop-types": {
"version": "15.7.11",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz",
"integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng=="
},
"node_modules/@types/react": {
"version": "18.2.45",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.45.tgz",
"integrity": "sha512-TtAxCNrlrBp8GoeEp1npd5g+d/OejJHFxS3OWmrPBMFaVQMSN0OFySozJio5BHxTuTeug00AVXVAjfDSfk+lUg==",
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "*",
"csstype": "^3.0.2"
}
},
"node_modules/@types/react-transition-group": {
"version": "4.4.10",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz",
"integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==",
"dependencies": {
"@types/react": "*"
}
},
"node_modules/@types/scheduler": {
"version": "0.16.8",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz",
"integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A=="
},
"node_modules/@typescript-eslint/parser": {
"version": "6.15.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.15.0.tgz",
@ -830,6 +859,11 @@
"node": ">= 8"
}
},
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
},
"node_modules/damerau-levenshtein": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
@ -923,6 +957,15 @@
"node": ">=6.0.0"
}
},
"node_modules/dom-helpers": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
"dependencies": {
"@babel/runtime": "^7.8.7",
"csstype": "^3.0.2"
}
},
"node_modules/emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
@ -2550,7 +2593,6 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -2827,11 +2869,37 @@
"node": ">= 0.8.0"
}
},
"node_modules/primeicons": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/primeicons/-/primeicons-6.0.1.tgz",
"integrity": "sha512-KDeO94CbWI4pKsPnYpA1FPjo79EsY9I+M8ywoPBSf9XMXoe/0crjbUK7jcQEDHuc0ZMRIZsxH3TYLv4TUtHmAA=="
},
"node_modules/primereact": {
"version": "10.2.1",
"resolved": "https://registry.npmjs.org/primereact/-/primereact-10.2.1.tgz",
"integrity": "sha512-F25053E1z+fod6V7AJ1Ix/DwSPkFQotk2+Idm0XkFsN+gQEywH7DgtbvNKpUA+LEq48h2+/WVK3D0V8IAm1Npg==",
"dependencies": {
"@types/react-transition-group": "^4.4.1",
"react-transition-group": "^4.4.1"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0",
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"dev": true,
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
@ -2893,8 +2961,22 @@
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"dev": true
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"node_modules/react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
"integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
"dependencies": {
"@babel/runtime": "^7.5.5",
"dom-helpers": "^5.0.1",
"loose-envify": "^1.4.0",
"prop-types": "^15.6.2"
},
"peerDependencies": {
"react": ">=16.6.0",
"react-dom": ">=16.6.0"
}
},
"node_modules/reflect.getprototypeof": {
"version": "1.0.4",
@ -2919,8 +3001,7 @@
"node_modules/regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
"dev": true
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
},
"node_modules/regexp.prototype.flags": {
"version": "1.5.1",

View File

@ -9,9 +9,11 @@
"lint": "next lint"
},
"dependencies": {
"next": "14.0.4",
"primeicons": "^6.0.1",
"primereact": "^10.2.1",
"react": "^18",
"react-dom": "^18",
"next": "14.0.4"
"react-dom": "^18"
},
"devDependencies": {
"eslint": "^8",

56
prisma/schema.prisma Normal file
View File

@ -0,0 +1,56 @@
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
npub String @unique
username String? @unique
purchased Purchase[]
role Role? @relation(fields: [roleId], references: [id])
roleId Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Role {
id Int @id @default(autoincrement())
name String @unique
users User[]
}
model Course {
id Int @id @default(autoincrement())
title String
description String
isFree Boolean @default(false)
resources Resource[]
purchases Purchase[]
noteId String? @unique
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Resource {
id Int @id @default(autoincrement())
title String
content String // Markdown content
course Course? @relation(fields: [courseId], references: [id])
noteId String? @unique
courseId Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Purchase {
id Int @id @default(autoincrement())
user User @relation(fields: [userId], references: [id])
userId Int
course Course @relation(fields: [courseId], references: [id])
courseId Int
amountPaid Int // in satoshis
paymentType String // Webln or NWC
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

BIN
public/plebdevs-guy.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,36 @@
import React from 'react';
import Image from 'next/image';
import { Button } from 'primereact/button';
import { Menubar } from 'primereact/menubar';
import 'primereact/resources/primereact.min.css'; // core css
import 'primeicons/primeicons.css'; // icons
import styles from './navbar.module.css';
const end = (
<Button
label="Login"
icon="pi pi-user"
className="p-button-rounded text-white"
/>
);
const start = (
<div className={styles.titleContainer}>
<Image
alt="logo"
src="/plebdevs-guy.jpg"
width={50}
height={50}
className={`${styles.logo}`}
/>
<h1 className={styles.title}>PlebDevs</h1>
</div>
);
const Navbar = () => {
return (
<Menubar start={start} end={end} />
);
};
export default Navbar;

View File

@ -0,0 +1,17 @@
.titleContainer {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.logo {
border-radius: 25px;
margin-right: 8px;
}
.title {
color: white;
font-size: 1.5rem;
font-weight: 600;
}

View File

@ -1,5 +1,11 @@
import '@/styles/globals.css'
import { PrimeReactProvider } from 'primereact/api';
// import '@/styles/globals.css'
import 'primereact/resources/themes/lara-dark-purple/theme.css';
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />
}
export default function MyApp({ Component, pageProps }) {
return (
<PrimeReactProvider>
<Component {...pageProps} />
</PrimeReactProvider>
);
}

View File

@ -1,9 +1,7 @@
import Head from 'next/head'
import Image from 'next/image'
import { Inter } from 'next/font/google'
import styles from '@/styles/Home.module.css'
import Navbar from '@/components/navbar/Navbar'
const inter = Inter({ subsets: ['latin'] })
export default function Home() {
return (
@ -14,100 +12,8 @@ export default function Home() {
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={`${styles.main} ${inter.className}`}>
<div className={styles.description}>
<p>
Get started by editing&nbsp;
<code className={styles.code}>src/pages/index.js</code>
</p>
<div>
<a
href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
By{' '}
<Image
src="/vercel.svg"
alt="Vercel Logo"
className={styles.vercelLogo}
width={100}
height={24}
priority
/>
</a>
</div>
</div>
<div className={styles.center}>
<Image
className={styles.logo}
src="/next.svg"
alt="Next.js Logo"
width={180}
height={37}
priority
/>
</div>
<div className={styles.grid}>
<a
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
className={styles.card}
target="_blank"
rel="noopener noreferrer"
>
<h2>
Docs <span>-&gt;</span>
</h2>
<p>
Find in-depth information about Next.js features and&nbsp;API.
</p>
</a>
<a
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
className={styles.card}
target="_blank"
rel="noopener noreferrer"
>
<h2>
Learn <span>-&gt;</span>
</h2>
<p>
Learn about Next.js in an interactive course with&nbsp;quizzes!
</p>
</a>
<a
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
className={styles.card}
target="_blank"
rel="noopener noreferrer"
>
<h2>
Templates <span>-&gt;</span>
</h2>
<p>
Discover and deploy boilerplate example Next.js&nbsp;projects.
</p>
</a>
<a
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
className={styles.card}
target="_blank"
rel="noopener noreferrer"
>
<h2>
Deploy <span>-&gt;</span>
</h2>
<p>
Instantly deploy your Next.js site to a shareable URL
with&nbsp;Vercel.
</p>
</a>
</div>
<main className={`${styles.main}`}>
<Navbar />
</main>
</>
)

View File

@ -1,9 +1,6 @@
.main {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
padding: 6rem;
min-height: 100vh;
}

View File

@ -104,4 +104,4 @@ a {
html {
color-scheme: dark;
}
}
}