mirror of
https://github.com/D4M13N-D3V/comissions-app-ui.git
synced 2025-03-13 07:45:07 +00:00
init
This commit is contained in:
commit
45ddebb984
5
.env.local.example
Normal file
5
.env.local.example
Normal file
@ -0,0 +1,5 @@
|
||||
AUTH0_ISSUER_BASE_URL="https://"
|
||||
AUTH0_CLIENT_ID=
|
||||
AUTH0_CLIENT_SECRET=
|
||||
AUTH0_BASE_URL="http://localhost:3000"
|
||||
AUTH0_SECRET=
|
14
.github/workflows/on-pr.yml
vendored
Normal file
14
.github/workflows/on-pr.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
name: on-pr
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
unit-test:
|
||||
runs-on: [Ubuntu-Latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install modules
|
||||
run: npm install
|
||||
|
||||
- name: Run tests
|
||||
run: npm run test
|
49
.github/workflows/on-push.yml
vendored
Normal file
49
.github/workflows/on-push.yml
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
name: on-pushed
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
build-image:
|
||||
runs-on: [ubuntu-latest]
|
||||
permissions: write-all
|
||||
env:
|
||||
docker_image_name: ghcr.io/data443/dim-search-web-ui
|
||||
steps:
|
||||
|
||||
- uses: gittools/actions/gitversion/setup@v0.9.15
|
||||
with:
|
||||
versionSpec: '5.x'
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: gittools/actions/gitversion/execute@v0.9.15
|
||||
with:
|
||||
useConfigFile: true
|
||||
configFilePath: GitVersion.yml
|
||||
|
||||
- name: login
|
||||
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login https://ghcr.io -u $ --password-stdin
|
||||
|
||||
- name: build
|
||||
run: docker build -t ${{ env.docker_image_name }}:${{ env.GitVersion_SemVer }} .
|
||||
|
||||
- name: tag latest
|
||||
run: docker tag ${{ env.docker_image_name }}:${{ env.GitVersion_SemVer }} ${{ env.docker_image_name }}:latest
|
||||
|
||||
- name: push
|
||||
run: docker push --all-tags ${{ env.docker_image_name }}
|
||||
|
||||
- name: tag branch
|
||||
run: |
|
||||
git tag ${{ env.GitVersion_SemVer }}
|
||||
git push origin ${{ env.GitVersion_SemVer }}
|
||||
|
||||
- name: release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
tag_name: ${{ env.GitVersion_SemVer }}
|
||||
generate_release_notes: true
|
20
.github/workflows/tag-stable-release.yml
vendored
Normal file
20
.github/workflows/tag-stable-release.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
name: tag-stable-release
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build-image:
|
||||
runs-on: [self-hosted, Linux, k8s]
|
||||
permissions:
|
||||
packages: write
|
||||
steps:
|
||||
- name: login into registry
|
||||
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login https://ghcr.io -u $ --password-stdin
|
||||
|
||||
- name: Tag latest
|
||||
env:
|
||||
docker_image_name: ghcr.io/data443/dim-search-web-ui
|
||||
run: |
|
||||
docker tag ${{ env.docker_image_name }}:${{ github.ref_name }} ${{ env.docker_image_name }}:stable
|
||||
docker push --all-tags ${{ env.docker_image_name }}
|
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Next.js
|
||||
/.next
|
||||
|
||||
#local env files
|
||||
.env*.local
|
||||
|
||||
/coverage
|
57
Dockerfile
Normal file
57
Dockerfile
Normal file
@ -0,0 +1,57 @@
|
||||
# Install dependencies only when needed
|
||||
FROM node:16-alpine AS deps
|
||||
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
||||
RUN apk add --no-cache libc6-compat
|
||||
WORKDIR /app
|
||||
|
||||
# Install dependencies based on the preferred package manager
|
||||
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
|
||||
RUN \
|
||||
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
|
||||
elif [ -f package-lock.json ]; then npm ci; \
|
||||
elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i; \
|
||||
else echo "Lockfile not found." && exit 1; \
|
||||
fi
|
||||
|
||||
|
||||
# Rebuild the source code only when needed
|
||||
FROM node:16-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
|
||||
# Next.js collects completely anonymous telemetry data about general usage.
|
||||
# Learn more here: https://nextjs.org/telemetry
|
||||
# Uncomment the following line in case you want to disable telemetry during the build.
|
||||
ENV NEXT_TELEMETRY_DISABLED 1
|
||||
|
||||
RUN yarn build
|
||||
|
||||
# If using npm comment out above and use below instead
|
||||
# RUN npm run build
|
||||
|
||||
# Production image, copy all the files and run next
|
||||
FROM node:16-alpine AS runner
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV production
|
||||
# Uncomment the following line in case you want to disable telemetry during runtime.
|
||||
ENV NEXT_TELEMETRY_DISABLED 1
|
||||
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
|
||||
COPY --from=builder /app/public ./public
|
||||
|
||||
# Automatically leverage output traces to reduce image size
|
||||
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
|
||||
USER nextjs
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENV PORT 3000
|
||||
|
||||
CMD ["node", "server.js"]
|
11
GitVersion.yml
Normal file
11
GitVersion.yml
Normal file
@ -0,0 +1,11 @@
|
||||
assembly-versioning-scheme: MajorMinorPatch
|
||||
mode: ContinuousDelivery
|
||||
branches: {}
|
||||
ignore:
|
||||
sha: []
|
||||
merge-message-formats: {}
|
||||
commit-message-incrementing: Enabled
|
||||
major-version-bump-message: "^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\\([\\w\\s-]*\\))?(!:|:.*\\n\\n((.+\\n)+\\n)?BREAKING CHANGE:\\s.+)"
|
||||
minor-version-bump-message: "^(feat)(\\([\\w\\s-]*\\))?:"
|
||||
patch-version-bump-message: "^(build|chore|ci|docs|fix|perf|refactor|revert|style|test)(\\([\\w\\s-]*\\))?:"
|
||||
|
68
README.md
Normal file
68
README.md
Normal file
@ -0,0 +1,68 @@
|
||||
# Next.js and Auth0 Example
|
||||
|
||||
This example shows how you can use `@auth0/nextjs-auth` to easily add authentication support to your Next.js application. It tries to cover a few topics:
|
||||
|
||||
- Signing in
|
||||
- Signing out
|
||||
- Loading the user on the server side and adding it as part of SSR ([`pages/advanced/ssr-profile.tsx`](pages/advanced/ssr-profile.tsx))
|
||||
- Loading the user on the client side and using fast/cached SSR pages ([`pages/index.tsx`](pages/index.tsx))
|
||||
- Loading the user on the client side and checking authentication CSR pages ([`pages/profile.tsx`](pages/profile.tsx))
|
||||
- Loading the user on the client side by accessing API (Serverless function) CSR pages ([`pages/advanced/api-profile.tsx`](pages/advanced/api-profile.tsx))
|
||||
- Creates route handlers under the hood that perform different parts of the authentication flow ([`pages/auth/[...auth0].tsx`](pages/auth/[...auth0].tsx))
|
||||
|
||||
Read more: [https://auth0.com/blog/ultimate-guide-nextjs-authentication-auth0/](https://auth0.com/blog/ultimate-guide-nextjs-authentication-auth0/)
|
||||
|
||||
## How to use
|
||||
|
||||
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example:
|
||||
|
||||
```bash
|
||||
npx create-next-app --example auth0 auth0-app
|
||||
```
|
||||
|
||||
```bash
|
||||
yarn create next-app --example auth0 auth0-app
|
||||
```
|
||||
|
||||
```bash
|
||||
pnpm create next-app --example auth0 auth0-app
|
||||
```
|
||||
|
||||
## Configuring Auth0
|
||||
|
||||
1. Go to the [Auth0 dashboard](https://manage.auth0.com/) and create a new application of type _Regular Web Applications_ and make sure to configure the following
|
||||
2. Go to the settings page of the application
|
||||
3. Configure the following settings:
|
||||
|
||||
- _Allowed Callback URLs_: Should be set to `http://localhost:3000/api/auth/callback` when testing locally or typically to `https://myapp.com/api/auth/callback` when deploying your application.
|
||||
- _Allowed Logout URLs_: Should be set to `http://localhost:3000/` when testing locally or typically to `https://myapp.com/` when deploying your application.
|
||||
|
||||
4. Save the settings
|
||||
|
||||
### Set up environment variables
|
||||
|
||||
To connect the app with Auth0, you'll need to add the settings from your Auth0 application as environment variables
|
||||
|
||||
Copy the `.env.local.example` file in this directory to `.env.local` (which will be ignored by Git):
|
||||
|
||||
```bash
|
||||
cp .env.local.example .env.local
|
||||
```
|
||||
|
||||
Then, open `.env.local` and add the missing environment variables:
|
||||
|
||||
- `AUTH0_ISSUER_BASE_URL` - Can be found in the Auth0 dashboard under `settings`. (Should be prefixed with `https://`)
|
||||
- `AUTH0_CLIENT_ID` - Can be found in the Auth0 dashboard under `settings`.
|
||||
- `AUTH0_CLIENT_SECRET` - Can be found in the Auth0 dashboard under `settings`.
|
||||
- `AUTH0_BASE_URL` - The base url of the application.
|
||||
- `AUTH0_SECRET` - Has to be at least 32 characters. You can use [this generator](https://generate-secret.vercel.app/32) to generate a value.
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
You can deploy this app to the cloud with [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).
|
||||
|
||||
### Deploy Your Local Project
|
||||
|
||||
To deploy your local project to Vercel, push it to GitHub/GitLab/Bitbucket and [import to Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example).
|
||||
|
||||
**Important**: When you import your project on Vercel, make sure to click on **Environment Variables** and set them to match your `.env.local` file.
|
7
additional.d.ts
vendored
Normal file
7
additional.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
export {};
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
__user: any;
|
||||
}
|
||||
}
|
31
components/artist.tsx
Normal file
31
components/artist.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
import * as React from 'react';
|
||||
import ImageListItem from '@mui/material/ImageListItem';
|
||||
import ImageListItemBar from '@mui/material/ImageListItemBar';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import InfoIcon from '@mui/icons-material/Info';
|
||||
import Image from 'next/image';
|
||||
|
||||
const Artist = ({artistId}) => {
|
||||
return (
|
||||
<ImageListItem key="https://images.unsplash.com/photo-1551963831-b3b1ca40c98e">
|
||||
<img
|
||||
srcSet={`https://images.unsplash.com/photo-1551963831-b3b1ca40c98e?w=248&fit=crop&auto=format&dpr=2 2x`}
|
||||
src={`https://images.unsplash.com/photo-1551963831-b3b1ca40c98e?w=248&fit=crop&auto=format`}
|
||||
alt={"Neroshi"}
|
||||
loading="lazy"
|
||||
/>
|
||||
<ImageListItemBar
|
||||
title={artistId}
|
||||
subtitle={"0 Stars (0 Reviews)"}
|
||||
actionIcon={
|
||||
<IconButton
|
||||
sx={{ color: 'rgba(255, 255, 255, 0.54)' }}
|
||||
aria-label={`info`}
|
||||
>
|
||||
<InfoIcon />
|
||||
</IconButton>
|
||||
}
|
||||
/>
|
||||
</ImageListItem>)
|
||||
}
|
||||
export default Artist
|
140
components/header.tsx
Normal file
140
components/header.tsx
Normal file
@ -0,0 +1,140 @@
|
||||
import * as React from 'react';
|
||||
import { useUser } from "@auth0/nextjs-auth0/client";
|
||||
import AppBar from '@mui/material/AppBar';
|
||||
import Box from '@mui/material/Box';
|
||||
import Toolbar from '@mui/material/Toolbar';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Menu from '@mui/material/Menu';
|
||||
import MenuIcon from '@mui/icons-material/Menu';
|
||||
import Container from '@mui/material/Container';
|
||||
import Avatar from '@mui/material/Avatar';
|
||||
import Button from '@mui/material/Button';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import Badge from "@mui/material/Badge";
|
||||
import NotificationsIcon from "@mui/icons-material/Notifications";
|
||||
import AdbIcon from '@mui/icons-material/Adb';
|
||||
import { Chip, Icon } from '@mui/material';
|
||||
import {
|
||||
NovuProvider,
|
||||
PopoverNotificationCenter,
|
||||
NotificationBell,
|
||||
} from '@novu/notification-center';
|
||||
|
||||
|
||||
type HeaderProps = {
|
||||
user?: any;
|
||||
loading: boolean;
|
||||
};
|
||||
|
||||
|
||||
const settings = ['Profile', 'Account', 'Dashboard', 'Logout'];
|
||||
|
||||
function ResponsiveAppBar() {
|
||||
const [anchorElNav, setAnchorElNav] = React.useState<null | HTMLElement>(null);
|
||||
const [anchorElUser, setAnchorElUser] = React.useState<null | HTMLElement>(null);
|
||||
|
||||
const handleOpenNavMenu = (event: React.MouseEvent<HTMLElement>) => {
|
||||
setAnchorElNav(event.currentTarget);
|
||||
};
|
||||
const handleOpenUserMenu = (event: React.MouseEvent<HTMLElement>) => {
|
||||
setAnchorElUser(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleCloseNavMenu = () => {
|
||||
setAnchorElNav(null);
|
||||
};
|
||||
|
||||
const handleCloseUserMenu = () => {
|
||||
setAnchorElUser(null);
|
||||
};
|
||||
|
||||
const { user, isLoading } = useUser();
|
||||
|
||||
return (
|
||||
<AppBar color="primary" position="static">
|
||||
<Container maxWidth="xl">
|
||||
<Toolbar disableGutters>
|
||||
<Box sx={{ flex:1, textAlign:"center" }}>
|
||||
<Typography
|
||||
href="/"
|
||||
variant="h6"
|
||||
noWrap
|
||||
color="secondary"
|
||||
component="a"
|
||||
sx={{
|
||||
mr: 2,
|
||||
paddingLeft: '1rem',
|
||||
display: { xs: 'none', md: 'flex' },
|
||||
fontFamily: 'monospace',
|
||||
fontWeight: 700,
|
||||
letterSpacing: '.3rem',
|
||||
textDecoration: 'none',
|
||||
}}
|
||||
>
|
||||
COMISSIONS.APP
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{
|
||||
user ? (
|
||||
<>
|
||||
<Box>
|
||||
<NovuProvider subscriberId={'on-boarding-subscriber-id-123'} applicationIdentifier={'9SKjzgN_odAF'}>
|
||||
<PopoverNotificationCenter colorScheme={'light'}>
|
||||
{({ unseenCount }) => <NotificationBell unseenCount={unseenCount} />}
|
||||
</PopoverNotificationCenter>
|
||||
</NovuProvider>
|
||||
</Box>
|
||||
<Box>
|
||||
<Chip
|
||||
onClick={handleOpenUserMenu}
|
||||
label={user.name}
|
||||
color="secondary"
|
||||
variant={'outlined'}
|
||||
style={{ marginLeft: '10px', minWidth: '5rem', maxWidth:'10rem' }}
|
||||
/>
|
||||
<Menu
|
||||
sx={{ mt: '45px' }}
|
||||
id="menu-appbar"
|
||||
anchorEl={anchorElUser}
|
||||
anchorOrigin={{
|
||||
vertical: 'top',
|
||||
horizontal: 'right',
|
||||
}}
|
||||
keepMounted
|
||||
transformOrigin={{
|
||||
vertical: 'top',
|
||||
horizontal: 'right',
|
||||
}}
|
||||
open={Boolean(anchorElUser)}
|
||||
onClose={handleCloseUserMenu}
|
||||
>
|
||||
<MenuItem key="logout" onClick={handleCloseUserMenu}>
|
||||
<Button color="primary" href="profile">Settings</Button>
|
||||
</MenuItem>
|
||||
<MenuItem key="logout" onClick={handleCloseUserMenu}>
|
||||
<Button color="error" href="/api/auth/logout">Logout</Button>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Box>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Button key="login" href='/api/auth/login' onClick={handleCloseNavMenu} sx={{ my: 2, display: 'block', color:"white" }}>
|
||||
Login
|
||||
</Button>
|
||||
<Button key="signup" href='/api/auth/login' onClick={handleCloseNavMenu} sx={{ my: 2, display: 'block', color:"white" }}>
|
||||
Signup
|
||||
</Button>
|
||||
</>
|
||||
|
||||
)}
|
||||
|
||||
</Toolbar>
|
||||
</Container>
|
||||
</AppBar>
|
||||
);
|
||||
}
|
||||
export default ResponsiveAppBar;
|
41
components/layout.tsx
Normal file
41
components/layout.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import Head from "next/head";
|
||||
import Header from "./header";
|
||||
|
||||
type LayoutProps = {
|
||||
user?: any;
|
||||
loading?: boolean;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
const Layout = ({ user, loading = false, children }: LayoutProps) => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Next.js with Auth0</title>
|
||||
</Head>
|
||||
|
||||
<Header user={user} loading={loading} />
|
||||
|
||||
<main>
|
||||
<div className="container">{children}</div>
|
||||
</main>
|
||||
|
||||
<style jsx>{`
|
||||
.container {
|
||||
max-width: 42rem;
|
||||
margin: 1.5rem auto;
|
||||
}
|
||||
`}</style>
|
||||
<style jsx global>{`
|
||||
body {
|
||||
margin: 0;
|
||||
color: #333;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
`}</style>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Layout;
|
9
interfaces/index.ts
Normal file
9
interfaces/index.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export type User = {
|
||||
email: string;
|
||||
email_verified: boolean;
|
||||
name: string;
|
||||
nickname: string;
|
||||
picture: string;
|
||||
sub: string;
|
||||
updated_at: string;
|
||||
};
|
5
next-env.d.ts
vendored
Normal file
5
next-env.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
2220
package-lock.json
generated
Normal file
2220
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
27
package.json
Normal file
27
package.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next",
|
||||
"build": "next build",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@auth0/nextjs-auth0": "^2.2.0",
|
||||
"@emotion/react": "^11.11.3",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@fontsource/roboto": "^5.0.8",
|
||||
"@mui/icons-material": "^5.15.6",
|
||||
"@mui/material": "^5.15.6",
|
||||
"@novu/notification-center": "^0.22.0",
|
||||
"next": "latest",
|
||||
"openapi-typescript-fetch": "^1.1.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.0.0",
|
||||
"@types/react": "^18.0.14",
|
||||
"@types/react-dom": "^18.0.5",
|
||||
"typescript": "^4.7.4"
|
||||
}
|
||||
}
|
38
pages/_app.tsx
Normal file
38
pages/_app.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import { UserProvider } from "@auth0/nextjs-auth0/client";
|
||||
import '@fontsource/roboto/300.css';
|
||||
import '@fontsource/roboto/400.css';
|
||||
import '@fontsource/roboto/500.css';
|
||||
import '@fontsource/roboto/700.css';
|
||||
import { createTheme } from '@mui/material/styles';
|
||||
import { green, purple } from '@mui/material/colors';
|
||||
import { ThemeProvider } from "@emotion/react";
|
||||
|
||||
const theme = createTheme({
|
||||
palette: {
|
||||
primary: {
|
||||
main: '#1D3555',
|
||||
},
|
||||
secondary: {
|
||||
main: '#E5BEED'
|
||||
},
|
||||
background: {
|
||||
default: '#3D3E46',
|
||||
paper: '#FAFAFF'
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
export default function App({ Component, pageProps }) {
|
||||
// optionally pass the 'user' prop from pages that require server-side
|
||||
// rendering to prepopulate the 'useUser' hook.
|
||||
const { user } = pageProps;
|
||||
|
||||
return (
|
||||
<UserProvider user={user}>
|
||||
<ThemeProvider theme={theme}>
|
||||
<Component {...pageProps} />
|
||||
</ThemeProvider>
|
||||
</UserProvider>
|
||||
);
|
||||
}
|
24
pages/about.tsx
Normal file
24
pages/about.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import { useUser } from "@auth0/nextjs-auth0/client";
|
||||
import Layout from "../components/layout";
|
||||
|
||||
const About = () => {
|
||||
const { user, isLoading } = useUser();
|
||||
|
||||
return (
|
||||
<Layout user={user} loading={isLoading}>
|
||||
<h1>About</h1>
|
||||
<p>
|
||||
This project shows different ways to display Profile info: using{" "}
|
||||
<i>Client rendered</i>, <i>Server rendered</i>, and <i>API rendered</i>
|
||||
</p>
|
||||
<p>
|
||||
Navigating between this page and <i>Home</i> is always pretty fast.
|
||||
However, when you navigate to the <i>Server rendered profile</i> page it
|
||||
takes more time because it uses SSR to fetch the user and then to
|
||||
display it
|
||||
</p>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export default About;
|
37
pages/advanced/api-profile.tsx
Normal file
37
pages/advanced/api-profile.tsx
Normal file
@ -0,0 +1,37 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useUser } from "@auth0/nextjs-auth0/client";
|
||||
import Layout from "../../components/layout";
|
||||
|
||||
const ApiProfile = () => {
|
||||
const { user, isLoading } = useUser();
|
||||
|
||||
const [data, setData] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const res = await fetch("/api/protected-api");
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
setData(data);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Layout user={user} loading={isLoading}>
|
||||
<h1>Profile</h1>
|
||||
|
||||
<div>
|
||||
<h3>Public page (client rendered)</h3>
|
||||
<p>We are fetching data on the client-side :</p>
|
||||
<p>By making request to '/api/protected-api' serverless function</p>
|
||||
<p>so without a valid session cookie will fail</p>
|
||||
<p>{JSON.stringify(data)}</p>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
// Public route.(CSR) also accessing API from the client-side.
|
||||
// data is not cached when redirecting between pages.
|
||||
export default ApiProfile;
|
26
pages/advanced/ssr-profile.tsx
Normal file
26
pages/advanced/ssr-profile.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import { withPageAuthRequired } from "@auth0/nextjs-auth0";
|
||||
import Layout from "../../components/layout";
|
||||
import { User } from "../../interfaces";
|
||||
|
||||
type ProfileProps = {
|
||||
user: User;
|
||||
};
|
||||
|
||||
export default function Profile({ user }: ProfileProps) {
|
||||
return (
|
||||
<Layout user={user}>
|
||||
<h1>Profile</h1>
|
||||
|
||||
<div>
|
||||
<h3>Profile (server rendered)</h3>
|
||||
<img src={user.picture} alt="user picture" />
|
||||
<p>nickname: {user.nickname}</p>
|
||||
<p>name: {user.name}</p>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
// Protected route, checking authentication status before rendering the page.(SSR)
|
||||
// It's slower than a static page with client side authentication
|
||||
export const getServerSideProps = withPageAuthRequired();
|
3
pages/api/auth/[...auth0].tsx
Normal file
3
pages/api/auth/[...auth0].tsx
Normal file
@ -0,0 +1,3 @@
|
||||
import { handleAuth } from "@auth0/nextjs-auth0";
|
||||
|
||||
export default handleAuth();
|
20
pages/api/protected-api.ts
Normal file
20
pages/api/protected-api.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { withApiAuthRequired, getSession } from "@auth0/nextjs-auth0";
|
||||
|
||||
// Serverless function
|
||||
// Protected API, requests to '/api/protected' without a valid session cookie will fail
|
||||
|
||||
async function handle(req, res) {
|
||||
const { user } = await getSession(req, res);
|
||||
|
||||
try {
|
||||
res.status(200).json({
|
||||
session: "true",
|
||||
id: user.sub,
|
||||
nickname: user.nickname,
|
||||
});
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: "Unable to fetch", description: e });
|
||||
}
|
||||
}
|
||||
|
||||
export default withApiAuthRequired(handle);
|
199
pages/index.tsx
Normal file
199
pages/index.tsx
Normal file
@ -0,0 +1,199 @@
|
||||
import { useUser } from "@auth0/nextjs-auth0/client";
|
||||
import Layout from "../components/layout";
|
||||
import TextField from '@mui/material/TextField';
|
||||
import Button from '@mui/material/Button';
|
||||
import { Typography } from "@mui/material";
|
||||
import Box from '@mui/material/Box';
|
||||
import ButtonGroup from '@mui/material/ButtonGroup';
|
||||
import styled from "@emotion/styled";
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import ImageList from '@mui/material/ImageList';
|
||||
import ImageListItem from '@mui/material/ImageListItem';
|
||||
import ImageListItemBar from '@mui/material/ImageListItemBar';
|
||||
import ListSubheader from '@mui/material/ListSubheader';
|
||||
import InfoIcon from '@mui/icons-material/Info';
|
||||
import Chip from "@mui/material/Chip";
|
||||
import { Fetcher } from "openapi-typescript-fetch";
|
||||
import { paths } from "../types";
|
||||
import Artist from "../components/artist";
|
||||
|
||||
|
||||
const StyledTextField = styled(TextField)({
|
||||
"& .MuiInputLabel-root": {
|
||||
right: 0,
|
||||
textAlign: "center"
|
||||
},
|
||||
"& .MuiInputLabel-shrink": {
|
||||
margin: "0 auto",
|
||||
position: "absolute",
|
||||
right: "0",
|
||||
left: "0",
|
||||
top: "-3px",
|
||||
width: "150px", // Need to give it a width so the positioning will work
|
||||
background: "white" // Add a white background as below we remove the legend that had the background so text is not meshing with the border
|
||||
// display: "none" //if you want to hide it completly
|
||||
},
|
||||
"& .MuiOutlinedInput-root.Mui-focused": {
|
||||
"& legend ": {
|
||||
display: "none"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const Home = () => {
|
||||
const { user, isLoading } = useUser();
|
||||
const fetcher = Fetcher.for<paths>()
|
||||
fetcher.configure({
|
||||
baseUrl: 'https://localhost.7148',
|
||||
init: {
|
||||
headers: {
|
||||
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<Layout user={user} loading={isLoading}>
|
||||
<>
|
||||
|
||||
{ user ? (
|
||||
<>
|
||||
<Box sx={{ m: 1 }} />
|
||||
<ButtonGroup fullWidth variant="contained" aria-label="outlined primary button group">
|
||||
<Button color="primary" fullWidth>Your Orders</Button>
|
||||
<Button color="secondary" fullWidth>Seller Dashboard</Button>
|
||||
</ButtonGroup>
|
||||
</>
|
||||
): (
|
||||
<Typography variant="h2" component="h2" textAlign="center">COMISSIONS.APP</Typography>
|
||||
)}
|
||||
<Box sx={{ m: 2 }} />
|
||||
<StyledTextField inputRef={input => input && input.focus()} sx={{input: {textAlign: "center"}}} fullWidth color="secondary" label="SEARCH ARTISTS" variant="outlined" />
|
||||
<Box sx={{ m: 4 }} />
|
||||
<div style={{ display: 'flex', justifyContent: 'center', marginTop: '10px' }}>
|
||||
{chips.map((chip, index) => (
|
||||
<Chip
|
||||
key={index}
|
||||
label={chip.label}
|
||||
color="primary"
|
||||
variant={chip.outlined ? 'outlined' : 'default'}
|
||||
onClick={() => console.log(`Clicked on ${chip.label}`)}
|
||||
style={{ margin: '0 5px' }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
|
||||
<ImageList sx={{ flex:1 }}>
|
||||
{itemData.map((item) => (
|
||||
<Artist artistId="1" />
|
||||
))}
|
||||
</ImageList>
|
||||
</>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
// fast/cached SSR page
|
||||
export default Home;
|
||||
|
||||
|
||||
const chips = [
|
||||
{ label: 'Category', outlined: true },
|
||||
{ label: 'Category', outlined: false },
|
||||
{ label: 'Category', outlined: true },
|
||||
{ label: 'Category', outlined: false },
|
||||
{ label: 'Category', outlined: true },
|
||||
{ label: 'Category', outlined: false },
|
||||
{ label: 'Category', outlined: true },
|
||||
{ label: 'Category', outlined: false },
|
||||
];
|
||||
|
||||
|
||||
const itemData = [
|
||||
{
|
||||
img: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e',
|
||||
title: 'Neroshi',
|
||||
author: '0 Stars (0 Reviews)',
|
||||
rows: 2,
|
||||
cols: 2,
|
||||
featured: true,
|
||||
},
|
||||
{
|
||||
img: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e',
|
||||
title: 'Neroshi',
|
||||
author: '0 Stars (0 Reviews)',
|
||||
},
|
||||
{
|
||||
img: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e',
|
||||
title: 'Neroshi',
|
||||
author: '0 Stars (0 Reviews)',
|
||||
},
|
||||
{
|
||||
img: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e',
|
||||
title: 'Neroshi',
|
||||
author: '0 Stars (0 Reviews)',
|
||||
rows: 2,
|
||||
cols: 2,
|
||||
featured: true,
|
||||
},
|
||||
{
|
||||
img: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e',
|
||||
title: 'Neroshi',
|
||||
author: '0 Stars (0 Reviews)',
|
||||
},
|
||||
{
|
||||
img: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e',
|
||||
title: 'Neroshi',
|
||||
author: '0 Stars (0 Reviews)',
|
||||
},
|
||||
{
|
||||
img: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e',
|
||||
title: 'Neroshi',
|
||||
author: '0 Stars (0 Reviews)',
|
||||
},
|
||||
{
|
||||
img: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e',
|
||||
title: 'Neroshi',
|
||||
author: '0 Stars (0 Reviews)',
|
||||
},
|
||||
{
|
||||
img: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e',
|
||||
title: 'Neroshi',
|
||||
author: '0 Stars (0 Reviews)',
|
||||
},
|
||||
{
|
||||
img: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e',
|
||||
title: 'Neroshi',
|
||||
author: '0 Stars (0 Reviews)',
|
||||
},
|
||||
{
|
||||
img: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e',
|
||||
title: 'Neroshi',
|
||||
author: '0 Stars (0 Reviews)',
|
||||
rows: 2,
|
||||
cols: 2,
|
||||
featured: true,
|
||||
},
|
||||
{
|
||||
img: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e',
|
||||
title: 'Neroshi',
|
||||
author: '0 Stars (0 Reviews)',
|
||||
},
|
||||
{
|
||||
img: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e',
|
||||
title: 'Neroshi',
|
||||
author: '0 Stars (0 Reviews)',
|
||||
},
|
||||
{
|
||||
img: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e',
|
||||
title: 'Neroshi',
|
||||
author: '0 Stars (0 Reviews)',
|
||||
},
|
||||
{
|
||||
img: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e',
|
||||
title: 'Neroshi',
|
||||
author: '0 Stars (0 Reviews)',
|
||||
},
|
||||
];
|
33
pages/profile.tsx
Normal file
33
pages/profile.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import { withPageAuthRequired } from "@auth0/nextjs-auth0/client";
|
||||
import Layout from "../components/layout";
|
||||
import { User } from "../interfaces";
|
||||
|
||||
type ProfileCardProps = {
|
||||
user: User;
|
||||
};
|
||||
|
||||
const ProfileCard = ({ user }: ProfileCardProps) => {
|
||||
return (
|
||||
<>
|
||||
<h1>Profile</h1>
|
||||
|
||||
<div>
|
||||
<h3>Profile (client rendered)</h3>
|
||||
<img src={user.picture} alt="user picture" />
|
||||
<p>nickname: {user.nickname}</p>
|
||||
<p>name: {user.name}</p>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const Profile = ({ user, isLoading }) => {
|
||||
return (
|
||||
<Layout user={user} loading={isLoading}>
|
||||
{isLoading ? <>Loading...</> : <ProfileCard user={user} />}
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
// Protected route, checking user authentication client-side.(CSR)
|
||||
export default withPageAuthRequired(Profile);
|
0
pages/theme.ts
Normal file
0
pages/theme.ts
Normal file
2555
swagger.json
Normal file
2555
swagger.json
Normal file
File diff suppressed because it is too large
Load Diff
20
tsconfig.json
Normal file
20
tsconfig.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true
|
||||
},
|
||||
"include": ["next-env.d.ts", "additional.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user