mirror of
https://github.com/fergalmoran/supanextail.git
synced 2025-12-22 01:10:01 +00:00
Clean V2 - Add sonarjs and unicorn js
This commit is contained in:
@@ -8,20 +8,22 @@
|
||||
"extends": [
|
||||
"next",
|
||||
"next/core-web-vitals",
|
||||
"plugin:@typescript-eslint/recommended-requiring-type-checking"
|
||||
"plugin:@typescript-eslint/recommended-requiring-type-checking",
|
||||
"plugin:sonarjs/recommended",
|
||||
"plugin:unicorn/recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
},
|
||||
"ecmaVersion": 12,
|
||||
"sourceType": "module"
|
||||
"project": [
|
||||
"./tsconfig.json"
|
||||
]
|
||||
},
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": [
|
||||
"@typescript-eslint",
|
||||
"cypress",
|
||||
"simple-import-sort",
|
||||
"prettier"
|
||||
"prettier",
|
||||
"sonarjs"
|
||||
],
|
||||
"rules": {
|
||||
"no-console": "off",
|
||||
@@ -61,6 +63,15 @@
|
||||
"allowHigherOrderFunctions": true,
|
||||
"allowConciseArrowFunctionExpressionsStartingWithVoid": true
|
||||
}
|
||||
],
|
||||
"unicorn/filename-case": [
|
||||
"error",
|
||||
{
|
||||
"cases": {
|
||||
"camelCase": true,
|
||||
"pascalCase": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
|
||||
@@ -9,25 +9,25 @@ import React, { useEffect, useState } from 'react';
|
||||
import Image from 'next/image';
|
||||
import { supabase } from 'utils/supabaseClient';
|
||||
|
||||
type AvatarProps = {
|
||||
type AvatarProperties = {
|
||||
url: string;
|
||||
size: number;
|
||||
onUpload: (filePath: string) => void;
|
||||
};
|
||||
|
||||
const Avatar = ({ url, size, onUpload }: AvatarProps): JSX.Element => {
|
||||
const customImgLoader = ({ src }: { src: string }): string => {
|
||||
return `${src}`;
|
||||
};
|
||||
|
||||
const Avatar = ({ url, size, onUpload }: AvatarProperties): JSX.Element => {
|
||||
const [avatarUrl, setAvatarUrl] = useState('');
|
||||
const [uploading, setUploading] = useState(false);
|
||||
|
||||
const customImgLoader = ({ src }: { src: string }) => {
|
||||
return `${src}`;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (url) downloadImage(url);
|
||||
if (url) void downloadImage(url);
|
||||
}, [url]);
|
||||
|
||||
async function downloadImage(path: string) {
|
||||
async function downloadImage(path: string): Promise<void> {
|
||||
try {
|
||||
const { data, error } = await supabase.storage
|
||||
.from('avatars')
|
||||
@@ -41,12 +41,14 @@ const Avatar = ({ url, size, onUpload }: AvatarProps): JSX.Element => {
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
console.log('Error downloading image: ', error.message);
|
||||
console.log('Error downloading image:', error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadAvatar(event: React.ChangeEvent<HTMLInputElement>) {
|
||||
async function uploadAvatar(
|
||||
event: React.ChangeEvent<HTMLInputElement>
|
||||
): Promise<void> {
|
||||
try {
|
||||
setUploading(true);
|
||||
|
||||
@@ -55,11 +57,11 @@ const Avatar = ({ url, size, onUpload }: AvatarProps): JSX.Element => {
|
||||
}
|
||||
|
||||
const file = event.target.files[0];
|
||||
const fileExt = file.name.split('.').pop();
|
||||
const fileName = `${Math.random()}.${fileExt}`;
|
||||
const fileExtension = file.name.split('.').pop();
|
||||
const fileName = fileExtension ? `${Math.random()}.${fileExtension}` : '';
|
||||
const filePath = `${fileName}`;
|
||||
|
||||
if (event.target.files[0].size > 150000) {
|
||||
if (event.target.files[0].size > 150_000) {
|
||||
alert('File is too big!');
|
||||
event.target.value = '';
|
||||
setUploading(false);
|
||||
|
||||
@@ -9,39 +9,47 @@ the axios.post here, line 18.
|
||||
import axios from 'axios';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
const Contact = (): JSX.Element => {
|
||||
const sendEmail = () => {
|
||||
const name = (document.getElementById('name') as HTMLInputElement).value;
|
||||
const email = (document.getElementById('email') as HTMLInputElement).value;
|
||||
const message = (document.getElementById('message') as HTMLInputElement)
|
||||
.value;
|
||||
const sendEmail = (): void => {
|
||||
const name = (document.querySelector('#name') as HTMLInputElement).value;
|
||||
const email = (document.querySelector('#email') as HTMLInputElement).value;
|
||||
const message = (document.querySelector('#message') as HTMLInputElement)
|
||||
.value;
|
||||
|
||||
if (name && email && message) {
|
||||
axios
|
||||
.post('/api/sendgrid', { email, name, message })
|
||||
.then((result) => {
|
||||
if (name && email && message) {
|
||||
axios
|
||||
.post('/api/sendgrid', { email, name, message })
|
||||
.then(
|
||||
(result: {
|
||||
data: {
|
||||
success: boolean;
|
||||
message: string;
|
||||
};
|
||||
}) => {
|
||||
if (result.data.success === true) {
|
||||
toast.success(result.data.message);
|
||||
(document.getElementById('name') as HTMLInputElement).value = '';
|
||||
(document.getElementById('email') as HTMLInputElement).value = '';
|
||||
(document.getElementById('message') as HTMLInputElement).value = '';
|
||||
(document.querySelector('#name') as HTMLInputElement).value = '';
|
||||
(document.querySelector('#email') as HTMLInputElement).value = '';
|
||||
(document.querySelector('#message') as HTMLInputElement).value = '';
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
} else {
|
||||
toast.info('Please fill all the fields ', {
|
||||
position: 'top-center',
|
||||
autoClose: 2000,
|
||||
hideProgressBar: true,
|
||||
closeOnClick: true,
|
||||
pauseOnHover: true,
|
||||
draggable: true,
|
||||
progress: undefined,
|
||||
}
|
||||
)
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
};
|
||||
} else {
|
||||
toast.info('Please fill all the fields ', {
|
||||
position: 'top-center',
|
||||
autoClose: 2000,
|
||||
hideProgressBar: true,
|
||||
closeOnClick: true,
|
||||
pauseOnHover: true,
|
||||
draggable: true,
|
||||
progress: undefined,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const Contact = (): JSX.Element => {
|
||||
return (
|
||||
<div className="max-w-xl px-5 py-10 m-auto">
|
||||
<div>
|
||||
@@ -87,8 +95,8 @@ const Contact = (): JSX.Element => {
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-primary btn-sm"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
sendEmail();
|
||||
}}>
|
||||
Submit{' '}
|
||||
|
||||
@@ -16,7 +16,7 @@ import { supabase } from '../utils/supabaseClient';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
type DashboardProps = {
|
||||
type DashboardProperties = {
|
||||
profile: { username: string; website: string; avatar_url: string };
|
||||
session: Session;
|
||||
planName: string;
|
||||
@@ -26,7 +26,7 @@ const Dashboard = ({
|
||||
profile,
|
||||
session,
|
||||
planName,
|
||||
}: DashboardProps): JSX.Element => {
|
||||
}: DashboardProperties): JSX.Element => {
|
||||
const router = useRouter();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [username, setUsername] = useState(profile?.username || '');
|
||||
@@ -48,7 +48,7 @@ const Dashboard = ({
|
||||
username: string;
|
||||
website: string;
|
||||
avatar_url: string;
|
||||
}) {
|
||||
}): Promise<void> {
|
||||
try {
|
||||
setLoading(true);
|
||||
const user = supabase.auth.user();
|
||||
@@ -89,7 +89,7 @@ const Dashboard = ({
|
||||
size={150}
|
||||
onUpload={(url) => {
|
||||
setAvatarUrl(url);
|
||||
updateProfile({ username, website, avatar_url: url });
|
||||
void updateProfile({ username, website, avatar_url: url });
|
||||
}}
|
||||
/>
|
||||
<div className="flex flex-col mb-5">
|
||||
@@ -125,7 +125,7 @@ const Dashboard = ({
|
||||
id="website"
|
||||
type="website"
|
||||
value={website || ''}
|
||||
onChange={(e) => setWebsite(e.target.value)}
|
||||
onChange={(event) => setWebsite(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -18,11 +18,11 @@ import Nav from './Nav';
|
||||
import { ToastContainer } from 'react-toastify';
|
||||
import { useAuth } from 'utils/AuthContext';
|
||||
|
||||
type LayoutProps = {
|
||||
type LayoutProperties = {
|
||||
children: JSX.Element;
|
||||
};
|
||||
|
||||
const Layout = ({ children }: LayoutProps): JSX.Element => {
|
||||
const Layout = ({ children }: LayoutProperties): JSX.Element => {
|
||||
const { user, signOut } = useAuth();
|
||||
|
||||
return (
|
||||
|
||||
@@ -17,7 +17,7 @@ const MailingList = (): JSX.Element => {
|
||||
const validateEmail = () => {
|
||||
// Regex patern for email validation
|
||||
const regex =
|
||||
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
/^(([^\s"(),.:;<>@[\\\]]+(\.[^\s"(),.:;<>@[\\\]]+)*)|(".+"))@((\[(?:\d{1,3}\.){3}\d{1,3}])|(([\dA-Za-z\-]+\.)+[A-Za-z]{2,}))$/;
|
||||
|
||||
if (regex.test(mail)) {
|
||||
// this is a valid email address
|
||||
@@ -42,8 +42,8 @@ const MailingList = (): JSX.Element => {
|
||||
setLoading(false);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -8,12 +8,12 @@ import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import Logo from 'public/logo.svg';
|
||||
|
||||
type NavProps = {
|
||||
type NavProperties = {
|
||||
user: Record<string, unknown>;
|
||||
signOut: () => void;
|
||||
};
|
||||
|
||||
const Nav = ({ user, signOut }: NavProps): JSX.Element => {
|
||||
const Nav = ({ user, signOut }: NavProperties): JSX.Element => {
|
||||
// Modify you menu directly here
|
||||
const NavMenu = (
|
||||
<>
|
||||
|
||||
@@ -2,12 +2,15 @@ import { Dialog, Transition } from '@headlessui/react';
|
||||
|
||||
import { Fragment } from 'react';
|
||||
|
||||
type PaymentModalProps = {
|
||||
type PaymentModalProperties = {
|
||||
open: boolean;
|
||||
setPayment: (arg0: boolean) => void;
|
||||
setPayment: (argument0: boolean) => void;
|
||||
};
|
||||
|
||||
const PaymentModal = ({ open, setPayment }: PaymentModalProps): JSX.Element => {
|
||||
const PaymentModal = ({
|
||||
open,
|
||||
setPayment,
|
||||
}: PaymentModalProperties): JSX.Element => {
|
||||
function closeModal() {
|
||||
setPayment(false);
|
||||
}
|
||||
|
||||
@@ -12,12 +12,12 @@ import { SupabaseClient } from '@supabase/supabase-js';
|
||||
import { supabase } from 'utils/supabaseClient';
|
||||
import { useAuth } from 'utils/AuthContext';
|
||||
|
||||
type ContainerProps = {
|
||||
type ContainerProperties = {
|
||||
children: JSX.Element;
|
||||
supabaseClient: SupabaseClient;
|
||||
};
|
||||
|
||||
const Container = ({ children }: ContainerProps): JSX.Element => {
|
||||
const Container = ({ children }: ContainerProperties): JSX.Element => {
|
||||
const { user, signOut } = useAuth();
|
||||
if (user)
|
||||
return (
|
||||
|
||||
@@ -4,13 +4,17 @@ This card is used on the landing page
|
||||
|
||||
import Image from 'next/image';
|
||||
|
||||
type CardLandingProps = {
|
||||
type CardLandingProperties = {
|
||||
image: string;
|
||||
title: string;
|
||||
text: string;
|
||||
};
|
||||
|
||||
const CardLanding = ({ image, title, text }: CardLandingProps): JSX.Element => {
|
||||
const CardLanding = ({
|
||||
image,
|
||||
title,
|
||||
text,
|
||||
}: CardLandingProperties): JSX.Element => {
|
||||
return (
|
||||
<div className="flex h-48 p-5 mb-5 w-80 sm:ml-5 bg-base-100">
|
||||
<div>
|
||||
|
||||
@@ -4,11 +4,11 @@ This card is used on the landing page
|
||||
|
||||
import { FiStar } from 'react-icons/fi';
|
||||
|
||||
type KeyFeatureProps = {
|
||||
type KeyFeatureProperties = {
|
||||
children: JSX.Element;
|
||||
};
|
||||
|
||||
const KeyFeature = ({ children }: KeyFeatureProps): JSX.Element => (
|
||||
const KeyFeature = ({ children }: KeyFeatureProperties): JSX.Element => (
|
||||
<div className="flex p-5 mb-5 italic shadow-sm bg-base-100">
|
||||
<div className="flex w-12 h-12 p-2 my-auto text-white rounded-sm bg-accent-focus">
|
||||
<FiStar className="m-auto text-2xl" />
|
||||
|
||||
@@ -3,7 +3,7 @@ import router from 'next/router';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useState } from 'react';
|
||||
|
||||
type LoginProps = {
|
||||
type LoginProperties = {
|
||||
resetPassword: (email: string) => Promise<{ error: { message: string } }>;
|
||||
signIn: ({}) => Promise<{
|
||||
data: Record<string, unknown>;
|
||||
@@ -11,24 +11,28 @@ type LoginProps = {
|
||||
}>;
|
||||
};
|
||||
|
||||
const Login = ({ resetPassword, signIn }: LoginProps): JSX.Element => {
|
||||
const Login = ({ resetPassword, signIn }: LoginProperties): JSX.Element => {
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [forgot, setForgot] = useState(false);
|
||||
|
||||
const resetPasswordLogin = () => {
|
||||
resetPassword(email).then((result: { error: { message: string } }) => {
|
||||
if (result.error) {
|
||||
toast.error(result.error.message);
|
||||
} else toast.success('Check your email to reset your password!');
|
||||
});
|
||||
const resetPasswordLogin = async (): Promise<void> => {
|
||||
await resetPassword(email).then(
|
||||
(result: { error: { message: string } }) => {
|
||||
if (result.error) {
|
||||
toast.error(result.error.message);
|
||||
} else toast.success('Check your email to reset your password!');
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const login = (e: React.SyntheticEvent<HTMLButtonElement>) => {
|
||||
e.preventDefault();
|
||||
const login = async (
|
||||
event: React.SyntheticEvent<HTMLButtonElement>
|
||||
): Promise<void> => {
|
||||
event.preventDefault();
|
||||
|
||||
// Handle the login. Go to the homepage if success or display an error.
|
||||
signIn({
|
||||
await signIn({
|
||||
email,
|
||||
password,
|
||||
}).then(
|
||||
@@ -37,7 +41,7 @@ const Login = ({ resetPassword, signIn }: LoginProps): JSX.Element => {
|
||||
error: { message: string };
|
||||
}) => {
|
||||
if (result.data) {
|
||||
router.push('/');
|
||||
void router.push('/');
|
||||
}
|
||||
if (result.error) {
|
||||
toast.error(result.error.message);
|
||||
@@ -97,7 +101,7 @@ const Login = ({ resetPassword, signIn }: LoginProps): JSX.Element => {
|
||||
<button
|
||||
className="w-full btn btn-primary"
|
||||
onClick={(event) => {
|
||||
login(event);
|
||||
void login(event);
|
||||
}}>
|
||||
Log in
|
||||
</button>
|
||||
@@ -113,7 +117,7 @@ const Login = ({ resetPassword, signIn }: LoginProps): JSX.Element => {
|
||||
className="flex items-center justify-center px-4 py-2 space-x-2 transition-colors duration-300 border rounded-md focus:outline-none border-base-200 group hover:bg-base-300"
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
signIn({ provider: 'google' });
|
||||
void signIn({ provider: 'google' });
|
||||
}}>
|
||||
<div className="text-base-content">
|
||||
<IoLogoGoogle />
|
||||
@@ -154,7 +158,7 @@ const Login = ({ resetPassword, signIn }: LoginProps): JSX.Element => {
|
||||
className="w-full btn btn-primary btn-sm"
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
resetPasswordLogin();
|
||||
void resetPasswordLogin();
|
||||
}}>
|
||||
Recover my password
|
||||
</button>
|
||||
|
||||
@@ -3,7 +3,7 @@ import router from 'next/router';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useState } from 'react';
|
||||
|
||||
type SignUpPanelProps = {
|
||||
type SignUpPanelProperties = {
|
||||
signIn: ({}) => Promise<{
|
||||
data: Record<string, unknown>;
|
||||
error: { message: string };
|
||||
@@ -14,19 +14,23 @@ type SignUpPanelProps = {
|
||||
}>;
|
||||
};
|
||||
|
||||
const SignUpPanel = ({ signIn, signUp }: SignUpPanelProps): JSX.Element => {
|
||||
const SignUpPanel = ({
|
||||
signIn,
|
||||
signUp,
|
||||
}: SignUpPanelProperties): JSX.Element => {
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
|
||||
const signup = (e: React.SyntheticEvent<HTMLButtonElement>) => {
|
||||
e.preventDefault();
|
||||
const signup = async (
|
||||
event: React.SyntheticEvent<HTMLButtonElement>
|
||||
): Promise<void> => {
|
||||
event.preventDefault();
|
||||
|
||||
// Handle the login. Go to the homepage if success or display an error.
|
||||
signUp({
|
||||
await signUp({
|
||||
email,
|
||||
password,
|
||||
}).then((result) => {
|
||||
console.log(result);
|
||||
if (result.error) {
|
||||
toast.error(result.error.message);
|
||||
} else if (result.data?.confirmation_sent_at) {
|
||||
@@ -35,7 +39,7 @@ const SignUpPanel = ({ signIn, signUp }: SignUpPanelProps): JSX.Element => {
|
||||
'A confirmation email has been sent to you, watch your mailbox!'
|
||||
);
|
||||
} else if (result.data) {
|
||||
router.push('/');
|
||||
void router.push('/');
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -78,7 +82,7 @@ const SignUpPanel = ({ signIn, signUp }: SignUpPanelProps): JSX.Element => {
|
||||
id="loginBtn"
|
||||
className="w-full btn btn-primary"
|
||||
onClick={(event) => {
|
||||
signup(event);
|
||||
void signup(event);
|
||||
}}>
|
||||
Sign Up
|
||||
</button>
|
||||
@@ -94,7 +98,7 @@ const SignUpPanel = ({ signIn, signUp }: SignUpPanelProps): JSX.Element => {
|
||||
className="flex items-center justify-center px-4 py-2 space-x-2 transition-colors duration-300 border rounded-md focus:outline-none border-base-200 group hover:bg-base-300"
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
signIn({ provider: 'google' });
|
||||
void signIn({ provider: 'google' });
|
||||
}}>
|
||||
<div className="text-base-content">
|
||||
<IoLogoGoogle />
|
||||
|
||||
13
package.json
13
package.json
@@ -7,7 +7,8 @@
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"eslint": "eslint . --fix",
|
||||
"test": "playwright test"
|
||||
"test": "playwright test",
|
||||
"update-types": "npx openapi-typescript https://vwkxoczhqygxvqzbhkmj.supabase.co/rest/v1/?apikey=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYzMDQwNzE1NCwiZXhwIjoxOTQ1OTgzMTU0fQ.VsWbay8ZrhDe3-elrlh7EGtJfW1INXlUywjeh6h2xgc --output types/database/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^1.4.2",
|
||||
@@ -16,7 +17,6 @@
|
||||
"@supabase/gotrue-js": "^1.21.7",
|
||||
"@supabase/supabase-js": "^1.29.1",
|
||||
"@types/node": "^17.0.4",
|
||||
"@types/react": "^17.0.38",
|
||||
"@types/react-dom": "^17.0.11",
|
||||
"axios": "^0.24.0",
|
||||
"cors": "^2.8.5",
|
||||
@@ -30,8 +30,7 @@
|
||||
"react-feather": "^2.0.9",
|
||||
"react-icons": "^4.3.1",
|
||||
"react-toastify": "^8.1.0",
|
||||
"stripe": "^8.195.0",
|
||||
"typescript": "^4.5.4"
|
||||
"stripe": "^8.195.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/eslint-plugin-next": "^12.0.7",
|
||||
@@ -39,6 +38,7 @@
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/express-rate-limit": "^5.1.3",
|
||||
"@types/micro": "^7.3.6",
|
||||
"@types/react": "^17.0.38",
|
||||
"@typescript-eslint/eslint-plugin": "^5.8.0",
|
||||
"autoprefixer": "^10.4.0",
|
||||
"eslint": "^8.5.0",
|
||||
@@ -53,8 +53,11 @@
|
||||
"eslint-plugin-react": "^7.28.0",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"eslint-plugin-simple-import-sort": "^7.0.0",
|
||||
"eslint-plugin-sonarjs": "^0.11.0",
|
||||
"eslint-plugin-unicorn": "^40.0.0",
|
||||
"postcss": "^8.4.5",
|
||||
"prettier": "^2.5.1",
|
||||
"tailwindcss": "^3.0.7"
|
||||
"tailwindcss": "^3.0.7",
|
||||
"typescript": "^4.5.4"
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,9 @@ import Document, {
|
||||
|
||||
class MyDocument extends Document {
|
||||
static async getInitialProps(
|
||||
ctx: DocumentContext
|
||||
context_: DocumentContext
|
||||
): Promise<DocumentInitialProps> {
|
||||
const initialProps = await Document.getInitialProps(ctx);
|
||||
|
||||
return initialProps;
|
||||
return await Document.getInitialProps(context_);
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
|
||||
@@ -8,8 +8,8 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { supabase } from 'utils/supabaseClient';
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
request: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
): Promise<void> {
|
||||
supabase.auth.api.setAuthCookie(req, res);
|
||||
supabase.auth.api.setAuthCookie(request, res);
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ import { supabase } from 'utils/supabaseClient';
|
||||
|
||||
// Example of how to verify and get user data server-side.
|
||||
const getUser = async (
|
||||
req: NextApiRequest,
|
||||
request: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
): Promise<void> => {
|
||||
const token = req.headers.token;
|
||||
const token = request.headers.token;
|
||||
|
||||
if (typeof token !== 'string') {
|
||||
return res.status(401).json({ error: 'Missing auth token.' });
|
||||
|
||||
@@ -19,23 +19,23 @@ const cors = initMiddleware(
|
||||
|
||||
const limiter = initMiddleware(
|
||||
rateLimit({
|
||||
windowMs: 30000, // 30sec
|
||||
windowMs: 30_000, // 30sec
|
||||
max: 2, // Max 2 request per 30 sec
|
||||
})
|
||||
);
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
request: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
): Promise<void> {
|
||||
await cors(req, res);
|
||||
await limiter(req, res);
|
||||
if (req.method === 'PUT') {
|
||||
await cors(request, res);
|
||||
await limiter(request, res);
|
||||
if (request.method === 'PUT') {
|
||||
axios
|
||||
.put(
|
||||
'https://api.sendgrid.com/v3/marketing/contacts',
|
||||
{
|
||||
contacts: [{ email: `${req.body.mail}` }],
|
||||
contacts: [{ email: `${request.body.mail}` }],
|
||||
list_ids: [process.env.SENDGRID_MAILING_ID],
|
||||
},
|
||||
{
|
||||
@@ -52,11 +52,11 @@ export default async function handler(
|
||||
'Your email has been succesfully added to the mailing list. Welcome 👋',
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch((error) => {
|
||||
res.status(500).send({
|
||||
message:
|
||||
'Oups, there was a problem with your subscription, please try again or contact us',
|
||||
error: err,
|
||||
error: error,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,22 +8,22 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import sgMail from '@sendgrid/mail';
|
||||
|
||||
const sendGrid = async (
|
||||
req: NextApiRequest,
|
||||
request: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
): Promise<void> => {
|
||||
if (req.method === 'POST') {
|
||||
if (request.method === 'POST') {
|
||||
sgMail.setApiKey(process.env.SENDGRID_SECRET || '');
|
||||
|
||||
const msg = {
|
||||
const message = {
|
||||
to: process.env.SENDGRID_MAILTO || '', // Change to your recipient
|
||||
from: process.env.SENDGRID_MAILFROM || '', // Change to your verified sender
|
||||
subject: `[${process.env.NEXT_PUBLIC_TITLE}] New message from ${req.body.name}`,
|
||||
text: req.body.message,
|
||||
reply_to: req.body.email,
|
||||
subject: `[${process.env.NEXT_PUBLIC_TITLE}] New message from ${request.body.name}`,
|
||||
text: request.body.message,
|
||||
reply_to: request.body.email,
|
||||
};
|
||||
|
||||
sgMail
|
||||
.send(msg)
|
||||
.send(message)
|
||||
.then(() => {
|
||||
res
|
||||
.status(200)
|
||||
|
||||
@@ -13,7 +13,7 @@ const cors = initMiddleware(
|
||||
|
||||
const limiter = initMiddleware(
|
||||
rateLimit({
|
||||
windowMs: 30000, // 30sec
|
||||
windowMs: 30_000, // 30sec
|
||||
max: 4, // Max 4 request per 30 sec
|
||||
})
|
||||
);
|
||||
@@ -24,26 +24,26 @@ const stripe = new Stripe(process.env.STRIPE_SECRET || '', {
|
||||
});
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
request: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
): Promise<void> {
|
||||
await cors(req, res);
|
||||
await limiter(req, res);
|
||||
if (req.method === 'POST') {
|
||||
const { priceId } = req.body;
|
||||
await cors(request, res);
|
||||
await limiter(request, res);
|
||||
if (request.method === 'POST') {
|
||||
const { priceId } = request.body;
|
||||
|
||||
// See https://stripe.com/docs/api/checkout/sessions/create
|
||||
// for additional parameters to pass.
|
||||
try {
|
||||
const session = req.body.customerId
|
||||
const session = request.body.customerId
|
||||
? await stripe.checkout.sessions.create({
|
||||
mode: req.body.pay_mode,
|
||||
mode: request.body.pay_mode,
|
||||
payment_method_types: ['card'],
|
||||
client_reference_id: req.body.userId,
|
||||
client_reference_id: request.body.userId,
|
||||
metadata: {
|
||||
priceId: req.body.priceId,
|
||||
priceId: request.body.priceId,
|
||||
},
|
||||
customer: req.body.customerId,
|
||||
customer: request.body.customerId,
|
||||
line_items: [
|
||||
{
|
||||
price: priceId,
|
||||
@@ -54,16 +54,16 @@ export default async function handler(
|
||||
// {CHECKOUT_SESSION_ID} is a string literal; do not change it!
|
||||
// the actual Session ID is returned in the query parameter when your customer
|
||||
// is redirected to the success page.
|
||||
success_url: `${req.headers.origin}/dashboard?session_id={CHECKOUT_SESSION_ID}`,
|
||||
cancel_url: `${req.headers.origin}/pricing`,
|
||||
success_url: `${request.headers.origin}/dashboard?session_id={CHECKOUT_SESSION_ID}`,
|
||||
cancel_url: `${request.headers.origin}/pricing`,
|
||||
})
|
||||
: await stripe.checkout.sessions.create({
|
||||
mode: 'subscription',
|
||||
payment_method_types: ['card'],
|
||||
customer_email: req.body.email,
|
||||
client_reference_id: req.body.userId,
|
||||
customer_email: request.body.email,
|
||||
client_reference_id: request.body.userId,
|
||||
metadata: {
|
||||
priceId: req.body.priceId,
|
||||
priceId: request.body.priceId,
|
||||
},
|
||||
line_items: [
|
||||
{
|
||||
@@ -75,16 +75,16 @@ export default async function handler(
|
||||
// {CHECKOUT_SESSION_ID} is a string literal; do not change it!
|
||||
// the actual Session ID is returned in the query parameter when your customer
|
||||
// is redirected to the success page.
|
||||
success_url: `${req.headers.origin}/dashboard?session_id={CHECKOUT_SESSION_ID}`,
|
||||
cancel_url: `${req.headers.origin}/pricing`,
|
||||
success_url: `${request.headers.origin}/dashboard?session_id={CHECKOUT_SESSION_ID}`,
|
||||
cancel_url: `${request.headers.origin}/pricing`,
|
||||
});
|
||||
res.status(200).send({ url: session.url });
|
||||
} catch (e: unknown) {
|
||||
} catch (error: unknown) {
|
||||
res.status(400);
|
||||
if (e instanceof Error) {
|
||||
if (error instanceof Error) {
|
||||
return res.send({
|
||||
error: {
|
||||
message: e.message,
|
||||
message: error.message,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ const cors = initMiddleware(
|
||||
|
||||
const limiter = initMiddleware(
|
||||
rateLimit({
|
||||
windowMs: 30000, // 30sec
|
||||
windowMs: 30_000, // 30sec
|
||||
max: 150, // Max 4 request per 30 sec
|
||||
})
|
||||
);
|
||||
@@ -27,16 +27,16 @@ const stripe = new Stripe(process.env.STRIPE_SECRET || '', {
|
||||
});
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
request: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
): Promise<void> {
|
||||
await cors(req, res);
|
||||
await limiter(req, res);
|
||||
if (req.method === 'POST') {
|
||||
const returnUrl = `${req.headers.origin}/dashboard`; // Stripe will return to the dashboard, you can change it
|
||||
await cors(request, res);
|
||||
await limiter(request, res);
|
||||
if (request.method === 'POST') {
|
||||
const returnUrl = `${request.headers.origin}/dashboard`; // Stripe will return to the dashboard, you can change it
|
||||
|
||||
const portalsession = await stripe.billingPortal.sessions.create({
|
||||
customer: req.body.customerId,
|
||||
customer: request.body.customerId,
|
||||
return_url: returnUrl,
|
||||
});
|
||||
res.status(200).send({ url: portalsession.url });
|
||||
|
||||
@@ -39,7 +39,7 @@ const supabase = createClient(
|
||||
|
||||
const limiter = initMiddleware(
|
||||
rateLimit({
|
||||
windowMs: 30000, // 30sec
|
||||
windowMs: 30_000, // 30sec
|
||||
max: 150, // Max 150 request per 30 sec
|
||||
})
|
||||
);
|
||||
@@ -52,18 +52,18 @@ const stripe = new Stripe(process.env.STRIPE_SECRET || '', {
|
||||
});
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
request: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
): Promise<void> {
|
||||
await cors(req, res);
|
||||
await limiter(req, res);
|
||||
await cors(request, res);
|
||||
await limiter(request, res);
|
||||
|
||||
if (req.method === 'POST') {
|
||||
if (request.method === 'POST') {
|
||||
// Retrieve the event by verifying the signature using the raw body and secret.
|
||||
let event: Stripe.Event;
|
||||
const buf = await buffer(req);
|
||||
const buf = await buffer(request);
|
||||
|
||||
const sig = req.headers['stripe-signature'] as string;
|
||||
const sig = request.headers['stripe-signature'] as string;
|
||||
|
||||
try {
|
||||
event = stripe.webhooks.constructEvent(
|
||||
@@ -71,8 +71,8 @@ export default async function handler(
|
||||
sig,
|
||||
process.env.STRIPE_WEBHOOK || ''
|
||||
);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
console.log(`⚠️ Webhook signature verification failed.`);
|
||||
console.log(
|
||||
`⚠️ Check the env file and enter the correct webhook secret.`
|
||||
@@ -118,7 +118,7 @@ export default async function handler(
|
||||
},
|
||||
])
|
||||
.then()
|
||||
.then(null, (err) => console.log('err: ', err)); // catch
|
||||
.then(null, (error) => console.log('err:', error)); // catch
|
||||
} else if (subscriptions?.length && subscriptions?.length > 0) {
|
||||
await supabase
|
||||
.from('subscriptions')
|
||||
@@ -130,7 +130,7 @@ export default async function handler(
|
||||
})
|
||||
.eq('id', dataObject.client_reference_id)
|
||||
.then()
|
||||
.then(null, (err) => console.log('err: ', err)); // catch
|
||||
.then(null, (error) => console.log('err:', error)); // catch
|
||||
}
|
||||
break;
|
||||
case 'customer.subscription.deleted':
|
||||
@@ -139,7 +139,7 @@ export default async function handler(
|
||||
.update({ paid_user: false })
|
||||
.eq('customer_id', dataObject.customer)
|
||||
.then()
|
||||
.then(null, (err) => console.log('err: ', err)); // catch
|
||||
.then(null, (error) => console.log('err:', error)); // catch
|
||||
break;
|
||||
case 'invoice.payment_failed':
|
||||
// If the payment fails or the customer does not have a valid payment method,
|
||||
|
||||
192
pnpm-lock.yaml
generated
192
pnpm-lock.yaml
generated
@@ -31,6 +31,8 @@ specifiers:
|
||||
eslint-plugin-react: ^7.28.0
|
||||
eslint-plugin-react-hooks: ^4.3.0
|
||||
eslint-plugin-simple-import-sort: ^7.0.0
|
||||
eslint-plugin-sonarjs: ^0.11.0
|
||||
eslint-plugin-unicorn: ^40.0.0
|
||||
express-rate-limit: ^6.0.1
|
||||
micro: ^9.3.4
|
||||
next: '>=12.0.7'
|
||||
@@ -53,7 +55,6 @@ dependencies:
|
||||
'@supabase/gotrue-js': 1.21.7
|
||||
'@supabase/supabase-js': 1.29.1
|
||||
'@types/node': 17.0.4
|
||||
'@types/react': 17.0.38
|
||||
'@types/react-dom': 17.0.11
|
||||
axios: 0.24.0
|
||||
cors: 2.8.5
|
||||
@@ -68,7 +69,6 @@ dependencies:
|
||||
react-icons: 4.3.1_react@17.0.2
|
||||
react-toastify: 8.1.0_react-dom@17.0.2+react@17.0.2
|
||||
stripe: 8.195.0
|
||||
typescript: 4.5.4
|
||||
|
||||
devDependencies:
|
||||
'@next/eslint-plugin-next': 12.0.7
|
||||
@@ -76,6 +76,7 @@ devDependencies:
|
||||
'@types/cors': 2.8.12
|
||||
'@types/express-rate-limit': 5.1.3
|
||||
'@types/micro': 7.3.6
|
||||
'@types/react': 17.0.38
|
||||
'@typescript-eslint/eslint-plugin': 5.8.0_eslint@8.5.0+typescript@4.5.4
|
||||
autoprefixer: 10.4.0_postcss@8.4.5
|
||||
eslint: 8.5.0
|
||||
@@ -90,9 +91,12 @@ devDependencies:
|
||||
eslint-plugin-react: 7.28.0_eslint@8.5.0
|
||||
eslint-plugin-react-hooks: 4.3.0_eslint@8.5.0
|
||||
eslint-plugin-simple-import-sort: 7.0.0_eslint@8.5.0
|
||||
eslint-plugin-sonarjs: 0.11.0_eslint@8.5.0
|
||||
eslint-plugin-unicorn: 40.0.0_eslint@8.5.0
|
||||
postcss: 8.4.5
|
||||
prettier: 2.5.1
|
||||
tailwindcss: 3.0.7_16a290f6d0e3717bf6d2667234aebd30
|
||||
typescript: 4.5.4
|
||||
|
||||
packages:
|
||||
|
||||
@@ -1099,13 +1103,16 @@ packages:
|
||||
/@types/node/17.0.4:
|
||||
resolution: {integrity: sha512-6xwbrW4JJiJLgF+zNypN5wr2ykM9/jHcL7rQ8fZe2vuftggjzZeRSM4OwRc6Xk8qWjwJ99qVHo/JgOGmomWRog==}
|
||||
|
||||
/@types/normalize-package-data/2.4.1:
|
||||
resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==}
|
||||
dev: true
|
||||
|
||||
/@types/parse-json/4.0.0:
|
||||
resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==}
|
||||
dev: true
|
||||
|
||||
/@types/prop-types/15.7.4:
|
||||
resolution: {integrity: sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==}
|
||||
dev: false
|
||||
|
||||
/@types/qs/6.9.7:
|
||||
resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==}
|
||||
@@ -1127,11 +1134,9 @@ packages:
|
||||
'@types/prop-types': 15.7.4
|
||||
'@types/scheduler': 0.16.2
|
||||
csstype: 3.0.9
|
||||
dev: false
|
||||
|
||||
/@types/scheduler/0.16.2:
|
||||
resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
|
||||
dev: false
|
||||
|
||||
/@types/serve-static/1.13.10:
|
||||
resolution: {integrity: sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==}
|
||||
@@ -1699,6 +1704,11 @@ packages:
|
||||
node-gyp-build: 4.3.0
|
||||
dev: false
|
||||
|
||||
/builtin-modules/3.2.0:
|
||||
resolution: {integrity: sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/builtin-status-codes/3.0.0:
|
||||
resolution: {integrity: sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=}
|
||||
dev: false
|
||||
@@ -1786,6 +1796,10 @@ packages:
|
||||
fsevents: 2.3.2
|
||||
dev: true
|
||||
|
||||
/ci-info/3.3.0:
|
||||
resolution: {integrity: sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==}
|
||||
dev: true
|
||||
|
||||
/cipher-base/1.0.4:
|
||||
resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==}
|
||||
dependencies:
|
||||
@@ -1797,6 +1811,13 @@ packages:
|
||||
resolution: {integrity: sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==}
|
||||
dev: false
|
||||
|
||||
/clean-regexp/1.0.0:
|
||||
resolution: {integrity: sha1-jffHquUf02h06PjQW5GAvBGj/tc=}
|
||||
engines: {node: '>=4'}
|
||||
dependencies:
|
||||
escape-string-regexp: 1.0.5
|
||||
dev: true
|
||||
|
||||
/clsx/1.1.1:
|
||||
resolution: {integrity: sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -1982,7 +2003,6 @@ packages:
|
||||
|
||||
/csstype/3.0.9:
|
||||
resolution: {integrity: sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==}
|
||||
dev: false
|
||||
|
||||
/d/1.0.1:
|
||||
resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==}
|
||||
@@ -2474,6 +2494,38 @@ packages:
|
||||
eslint: 8.5.0
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-sonarjs/0.11.0_eslint@8.5.0:
|
||||
resolution: {integrity: sha512-ei/WuZiL0wP+qx2KrxKyZs3+eDbxiGAhFSm3GKCOOAUkg+G2ny6TSXDB2j67tvyqHefi+eoQsAgGQvz+nEtIBw==}
|
||||
engines: {node: '>=12'}
|
||||
peerDependencies:
|
||||
eslint: ^5.0.0 || ^6.0.0 || ^7.0.0|| ^8.0.0
|
||||
dependencies:
|
||||
eslint: 8.5.0
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-unicorn/40.0.0_eslint@8.5.0:
|
||||
resolution: {integrity: sha512-5GRXISfBk8jMmYk1eeNDw8zSRnWTxBjWkzx2Prre6E2/yLu2twozZ3EomLWCBu9nWms/ZE361BItyMQwfnG1qA==}
|
||||
engines: {node: '>=12'}
|
||||
peerDependencies:
|
||||
eslint: '>=7.32.0'
|
||||
dependencies:
|
||||
'@babel/helper-validator-identifier': 7.15.7
|
||||
ci-info: 3.3.0
|
||||
clean-regexp: 1.0.0
|
||||
eslint: 8.5.0
|
||||
eslint-utils: 3.0.0_eslint@8.5.0
|
||||
esquery: 1.4.0
|
||||
indent-string: 4.0.0
|
||||
is-builtin-module: 3.1.0
|
||||
lodash: 4.17.21
|
||||
pluralize: 8.0.0
|
||||
read-pkg-up: 7.0.1
|
||||
regexp-tree: 0.1.24
|
||||
safe-regex: 2.1.1
|
||||
semver: 7.3.5
|
||||
strip-indent: 3.0.0
|
||||
dev: true
|
||||
|
||||
/eslint-scope/5.1.1:
|
||||
resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
@@ -2725,7 +2777,6 @@ packages:
|
||||
dependencies:
|
||||
locate-path: 5.0.0
|
||||
path-exists: 4.0.0
|
||||
dev: false
|
||||
|
||||
/flat-cache/3.0.4:
|
||||
resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==}
|
||||
@@ -2929,6 +2980,10 @@ packages:
|
||||
minimalistic-crypto-utils: 1.0.1
|
||||
dev: false
|
||||
|
||||
/hosted-git-info/2.8.9:
|
||||
resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
|
||||
dev: true
|
||||
|
||||
/http-errors/1.6.2:
|
||||
resolution: {integrity: sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=}
|
||||
engines: {node: '>= 0.6'}
|
||||
@@ -3032,6 +3087,11 @@ packages:
|
||||
engines: {node: '>=0.8.19'}
|
||||
dev: true
|
||||
|
||||
/indent-string/4.0.0:
|
||||
resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/inflight/1.0.6:
|
||||
resolution: {integrity: sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=}
|
||||
dependencies:
|
||||
@@ -3088,6 +3148,13 @@ packages:
|
||||
call-bind: 1.0.2
|
||||
has-tostringtag: 1.0.0
|
||||
|
||||
/is-builtin-module/3.1.0:
|
||||
resolution: {integrity: sha512-OV7JjAgOTfAFJmHZLvpSTb4qi0nIILDV1gWPYDnDJUTNFM5aGlRAhk4QcT8i7TuAleeEV5Fdkqn3t4mS+Q11fg==}
|
||||
engines: {node: '>=6'}
|
||||
dependencies:
|
||||
builtin-modules: 3.2.0
|
||||
dev: true
|
||||
|
||||
/is-callable/1.2.4:
|
||||
resolution: {integrity: sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -3364,7 +3431,6 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
p-locate: 4.1.0
|
||||
dev: false
|
||||
|
||||
/lodash.merge/4.6.2:
|
||||
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||
@@ -3374,6 +3440,10 @@ packages:
|
||||
resolution: {integrity: sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=}
|
||||
dev: false
|
||||
|
||||
/lodash/4.17.21:
|
||||
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
||||
dev: true
|
||||
|
||||
/loose-envify/1.4.0:
|
||||
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
|
||||
hasBin: true
|
||||
@@ -3444,6 +3514,11 @@ packages:
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/min-indent/1.0.1:
|
||||
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/minimalistic-assert/1.0.1:
|
||||
resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==}
|
||||
dev: false
|
||||
@@ -3612,6 +3687,15 @@ packages:
|
||||
resolution: {integrity: sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==}
|
||||
dev: true
|
||||
|
||||
/normalize-package-data/2.5.0:
|
||||
resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
|
||||
dependencies:
|
||||
hosted-git-info: 2.8.9
|
||||
resolve: 1.20.0
|
||||
semver: 5.7.1
|
||||
validate-npm-package-license: 3.0.4
|
||||
dev: true
|
||||
|
||||
/normalize-path/3.0.0:
|
||||
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -3731,7 +3815,6 @@ packages:
|
||||
engines: {node: '>=6'}
|
||||
dependencies:
|
||||
p-try: 2.2.0
|
||||
dev: false
|
||||
|
||||
/p-limit/3.1.0:
|
||||
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
|
||||
@@ -3752,7 +3835,6 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
p-limit: 2.3.0
|
||||
dev: false
|
||||
|
||||
/p-try/1.0.0:
|
||||
resolution: {integrity: sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=}
|
||||
@@ -3762,7 +3844,6 @@ packages:
|
||||
/p-try/2.2.0:
|
||||
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/pako/1.0.11:
|
||||
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
|
||||
@@ -3807,7 +3888,6 @@ packages:
|
||||
/path-exists/4.0.0:
|
||||
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
||||
engines: {node: '>=8'}
|
||||
dev: false
|
||||
|
||||
/path-is-absolute/1.0.1:
|
||||
resolution: {integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18=}
|
||||
@@ -3910,6 +3990,11 @@ packages:
|
||||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/pluralize/8.0.0:
|
||||
resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/pngjs/4.0.1:
|
||||
resolution: {integrity: sha512-rf5+2/ioHeQxR6IxuYNYGFytUyG3lma/WW1nsmjeHlWwtb2aByla6dkVc8pmJ9nplzkTA0q2xx7mMWrOTqT4Gg==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
@@ -4183,6 +4268,25 @@ packages:
|
||||
object-assign: 4.1.1
|
||||
dev: false
|
||||
|
||||
/read-pkg-up/7.0.1:
|
||||
resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
find-up: 4.1.0
|
||||
read-pkg: 5.2.0
|
||||
type-fest: 0.8.1
|
||||
dev: true
|
||||
|
||||
/read-pkg/5.2.0:
|
||||
resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
'@types/normalize-package-data': 2.4.1
|
||||
normalize-package-data: 2.5.0
|
||||
parse-json: 5.2.0
|
||||
type-fest: 0.6.0
|
||||
dev: true
|
||||
|
||||
/readable-stream/3.6.0:
|
||||
resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==}
|
||||
engines: {node: '>= 6'}
|
||||
@@ -4213,6 +4317,11 @@ packages:
|
||||
/regenerator-runtime/0.13.9:
|
||||
resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==}
|
||||
|
||||
/regexp-tree/0.1.24:
|
||||
resolution: {integrity: sha512-s2aEVuLhvnVJW6s/iPgEGK6R+/xngd2jNQ+xy4bXNDKxZKJH6jpPHY6kVeVv1IeLCHgswRj+Kl3ELaDjG6V1iw==}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/regexp.prototype.flags/1.3.1:
|
||||
resolution: {integrity: sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -4287,6 +4396,12 @@ packages:
|
||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||
dev: false
|
||||
|
||||
/safe-regex/2.1.1:
|
||||
resolution: {integrity: sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==}
|
||||
dependencies:
|
||||
regexp-tree: 0.1.24
|
||||
dev: true
|
||||
|
||||
/safer-buffer/2.1.2:
|
||||
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
||||
dev: false
|
||||
@@ -4298,6 +4413,11 @@ packages:
|
||||
object-assign: 4.1.1
|
||||
dev: false
|
||||
|
||||
/semver/5.7.1:
|
||||
resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/semver/6.3.0:
|
||||
resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==}
|
||||
hasBin: true
|
||||
@@ -4429,6 +4549,28 @@ packages:
|
||||
whatwg-url: 7.1.0
|
||||
dev: false
|
||||
|
||||
/spdx-correct/3.1.1:
|
||||
resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==}
|
||||
dependencies:
|
||||
spdx-expression-parse: 3.0.1
|
||||
spdx-license-ids: 3.0.11
|
||||
dev: true
|
||||
|
||||
/spdx-exceptions/2.3.0:
|
||||
resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==}
|
||||
dev: true
|
||||
|
||||
/spdx-expression-parse/3.0.1:
|
||||
resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==}
|
||||
dependencies:
|
||||
spdx-exceptions: 2.3.0
|
||||
spdx-license-ids: 3.0.11
|
||||
dev: true
|
||||
|
||||
/spdx-license-ids/3.0.11:
|
||||
resolution: {integrity: sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==}
|
||||
dev: true
|
||||
|
||||
/stack-utils/2.0.5:
|
||||
resolution: {integrity: sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -4516,6 +4658,13 @@ packages:
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/strip-indent/3.0.0:
|
||||
resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
min-indent: 1.0.1
|
||||
dev: true
|
||||
|
||||
/strip-json-comments/3.1.1:
|
||||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -4694,11 +4843,21 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
/type-fest/0.6.0:
|
||||
resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==}
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/type-fest/0.7.1:
|
||||
resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==}
|
||||
engines: {node: '>=8'}
|
||||
dev: false
|
||||
|
||||
/type-fest/0.8.1:
|
||||
resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==}
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/type/1.2.0:
|
||||
resolution: {integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==}
|
||||
dev: false
|
||||
@@ -4717,7 +4876,7 @@ packages:
|
||||
resolution: {integrity: sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==}
|
||||
engines: {node: '>=4.2.0'}
|
||||
hasBin: true
|
||||
dev: false
|
||||
dev: true
|
||||
|
||||
/unbox-primitive/1.0.1:
|
||||
resolution: {integrity: sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==}
|
||||
@@ -4773,6 +4932,13 @@ packages:
|
||||
resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==}
|
||||
dev: true
|
||||
|
||||
/validate-npm-package-license/3.0.4:
|
||||
resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
|
||||
dependencies:
|
||||
spdx-correct: 3.1.1
|
||||
spdx-expression-parse: 3.0.1
|
||||
dev: true
|
||||
|
||||
/vary/1.1.2:
|
||||
resolution: {integrity: sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
@@ -1,76 +1,76 @@
|
||||
module.exports = {
|
||||
mode: 'jit',
|
||||
purge: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
|
||||
darkMode: false, // or 'media' or 'class'
|
||||
theme: {
|
||||
fontFamily: {
|
||||
title: ['Poppins'],
|
||||
body: ['Inter'],
|
||||
},
|
||||
extend: {},
|
||||
},
|
||||
variants: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [require('daisyui')],
|
||||
daisyui: {
|
||||
themes: [
|
||||
{
|
||||
supaTheme: {
|
||||
primary: '#00B8F0',
|
||||
'primary-focus': '#009de0',
|
||||
'primary-content': '#ffffff',
|
||||
mode: 'jit',
|
||||
purge: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
|
||||
darkMode: false, // or 'media' or 'class'
|
||||
theme: {
|
||||
fontFamily: {
|
||||
title: ['Poppins'],
|
||||
body: ['Inter'],
|
||||
},
|
||||
extend: {},
|
||||
},
|
||||
variants: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [require('daisyui')],
|
||||
daisyui: {
|
||||
themes: [
|
||||
{
|
||||
supaTheme: {
|
||||
primary: '#00B8F0',
|
||||
'primary-focus': '#009de0',
|
||||
'primary-content': '#ffffff',
|
||||
|
||||
secondary: '#f03800',
|
||||
'secondary-focus': '#e22f00',
|
||||
'secondary-content': '#ffffff',
|
||||
secondary: '#f03800',
|
||||
'secondary-focus': '#e22f00',
|
||||
'secondary-content': '#ffffff',
|
||||
|
||||
accent: '#00f0b0',
|
||||
'accent-focus': '#00e28a',
|
||||
'accent-content': '#ffffff',
|
||||
accent: '#00f0b0',
|
||||
'accent-focus': '#00e28a',
|
||||
'accent-content': '#ffffff',
|
||||
|
||||
neutral: '#3d4451',
|
||||
'neutral-focus': '#2a2e37',
|
||||
'neutral-content': '#ffffff',
|
||||
neutral: '#3d4451',
|
||||
'neutral-focus': '#2a2e37',
|
||||
'neutral-content': '#ffffff',
|
||||
|
||||
'base-100': '#ffffff',
|
||||
'base-200': '#767676',
|
||||
'base-300': '#d1d5db',
|
||||
'base-content': '#1f2937',
|
||||
'base-100': '#ffffff',
|
||||
'base-200': '#767676',
|
||||
'base-300': '#d1d5db',
|
||||
'base-content': '#1f2937',
|
||||
|
||||
info: '#2094f3' /* Info */,
|
||||
success: '#009485' /* Success */,
|
||||
warning: '#ff9900' /* Warning */,
|
||||
error: '#ff5724' /* Error */,
|
||||
},
|
||||
dark: {
|
||||
primary: '#00B8F0',
|
||||
'primary-focus': '#009de0',
|
||||
'primary-content': '#ffffff',
|
||||
info: '#2094f3' /* Info */,
|
||||
success: '#009485' /* Success */,
|
||||
warning: '#ff9900' /* Warning */,
|
||||
error: '#ff5724' /* Error */,
|
||||
},
|
||||
dark: {
|
||||
primary: '#00B8F0',
|
||||
'primary-focus': '#009de0',
|
||||
'primary-content': '#ffffff',
|
||||
|
||||
secondary: '#f03800',
|
||||
'secondary-focus': '#e22f00',
|
||||
'secondary-content': '#ffffff',
|
||||
secondary: '#f03800',
|
||||
'secondary-focus': '#e22f00',
|
||||
'secondary-content': '#ffffff',
|
||||
|
||||
accent: '#00f0b0',
|
||||
'accent-focus': '#00e28a',
|
||||
'accent-content': '#ffffff',
|
||||
accent: '#00f0b0',
|
||||
'accent-focus': '#00e28a',
|
||||
'accent-content': '#ffffff',
|
||||
|
||||
neutral: '#3d4451',
|
||||
'neutral-focus': '#2a2e37',
|
||||
'neutral-content': '#ffffff',
|
||||
neutral: '#3d4451',
|
||||
'neutral-focus': '#2a2e37',
|
||||
'neutral-content': '#ffffff',
|
||||
|
||||
'base-100': '#2A2E37',
|
||||
'base-200': '#EBECF0',
|
||||
'base-300': '#16181D',
|
||||
'base-content': '#EBECF0',
|
||||
'base-100': '#2A2E37',
|
||||
'base-200': '#EBECF0',
|
||||
'base-300': '#16181D',
|
||||
'base-content': '#EBECF0',
|
||||
|
||||
info: '#2094f3',
|
||||
success: '#009485',
|
||||
warning: '#ff9900',
|
||||
error: '#ff5724',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
info: '#2094f3',
|
||||
success: '#009485',
|
||||
warning: '#ff9900',
|
||||
error: '#ff5724',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
|
||||
/* Module Resolution Options */
|
||||
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
"baseUrl": "./", /* Base directory to resolve non-absolute module names. */ /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
"baseUrl": "./", /* Base directory to resolve non-absolute module names. */ /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||
// "types": [], /* Type declaration files to be included in compilation. */
|
||||
"allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
@@ -46,7 +46,7 @@
|
||||
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
"inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||
"inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ /* Experimental Options */// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
"inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ /* Experimental Options */ // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||
/* Advanced Options */
|
||||
"skipLibCheck": true, /* Skip type checking of declaration files. */
|
||||
@@ -65,9 +65,10 @@
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx"
|
||||
"**/*.tsx",
|
||||
"utils/AuthContext.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
54
types/supabase.ts
Normal file
54
types/supabase.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* This file was auto-generated by openapi-typescript.
|
||||
* Do not make direct changes to the file.
|
||||
*/
|
||||
|
||||
export interface paths {
|
||||
'/': {
|
||||
get: {
|
||||
responses: {
|
||||
/** OK */
|
||||
200: unknown;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface parameters {
|
||||
/**
|
||||
* @description Preference
|
||||
* @enum {string}
|
||||
*/
|
||||
preferParams: 'params=single-object';
|
||||
/**
|
||||
* @description Preference
|
||||
* @enum {string}
|
||||
*/
|
||||
preferReturn: 'return=representation' | 'return=minimal' | 'return=none';
|
||||
/**
|
||||
* @description Preference
|
||||
* @enum {string}
|
||||
*/
|
||||
preferCount: 'count=none';
|
||||
/** @description Filtering Columns */
|
||||
select: string;
|
||||
/** @description On Conflict */
|
||||
on_conflict: string;
|
||||
/** @description Ordering */
|
||||
order: string;
|
||||
/** @description Limiting and Pagination */
|
||||
range: string;
|
||||
/**
|
||||
* @description Limiting and Pagination
|
||||
* @default items
|
||||
*/
|
||||
rangeUnit: string;
|
||||
/** @description Limiting and Pagination */
|
||||
offset: string;
|
||||
/** @description Limiting and Pagination */
|
||||
limit: string;
|
||||
}
|
||||
|
||||
export interface operations {}
|
||||
|
||||
export interface external {}
|
||||
@@ -1,63 +0,0 @@
|
||||
import React, { createContext, useContext, useEffect, useState } from 'react';
|
||||
|
||||
import { supabase } from 'utils/supabaseClient';
|
||||
|
||||
// create a context for authentication
|
||||
const AuthContext = createContext();
|
||||
|
||||
export const AuthProvider = ({ children }) => {
|
||||
const [user, setUser] = useState();
|
||||
const [session, setSession] = useState();
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
// Check active sessions and sets the user
|
||||
const session = supabase.auth.session();
|
||||
|
||||
setUser(session?.user ?? null);
|
||||
setSession(session ?? null);
|
||||
setLoading(false);
|
||||
|
||||
// Listen for changes on auth state (logged in, signed out, etc.)
|
||||
const { data: listener } = supabase.auth.onAuthStateChange(
|
||||
async (event, session) => {
|
||||
if ((event === 'SIGNED_OUT') | (event === 'SIGNED_IN')) {
|
||||
fetch('/api/auth', {
|
||||
method: 'POST',
|
||||
headers: new Headers({ 'Content-Type': 'application/json' }),
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({ event, session }),
|
||||
}).then((res) => res.json());
|
||||
}
|
||||
if (event === 'USER_UPDATED') {
|
||||
}
|
||||
setUser(session?.user ?? null);
|
||||
setSession(session ?? null);
|
||||
setLoading(false);
|
||||
}
|
||||
);
|
||||
|
||||
return () => {
|
||||
listener?.unsubscribe();
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Will be passed down to Signup, Login and Dashboard components
|
||||
const value = {
|
||||
signUp: (data) => supabase.auth.signUp(data),
|
||||
signIn: (data) => supabase.auth.signIn(data),
|
||||
signOut: () => supabase.auth.signOut(),
|
||||
resetPassword: (data) => supabase.auth.api.resetPasswordForEmail(data),
|
||||
user,
|
||||
session,
|
||||
};
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={value}>
|
||||
{!loading && children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
// export the useAuth hook
|
||||
export const useAuth = () => useContext(AuthContext);
|
||||
85
utils/AuthContext.tsx
Normal file
85
utils/AuthContext.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import {
|
||||
ReactNode,
|
||||
createContext,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import { UserCredentials } from '@supabase/gotrue-js';
|
||||
import { supabase } from 'utils/supabaseClient';
|
||||
|
||||
type authContextType = {
|
||||
user: boolean;
|
||||
login: () => void;
|
||||
logout: () => void;
|
||||
};
|
||||
|
||||
type Properties = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
const authContextDefaultValues: authContextType = {
|
||||
user: false,
|
||||
login: () => {},
|
||||
logout: () => {},
|
||||
};
|
||||
|
||||
// create a context for authentication
|
||||
const AuthContext = createContext<authContextType>(authContextDefaultValues);
|
||||
|
||||
export const AuthProvider = ({ children }: Properties): JSX.Element => {
|
||||
const [user, setUser] = useState(supabase.auth.session()?.user);
|
||||
const [session, setSession] = useState(supabase.auth.session());
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
// Check active sessions and sets the user
|
||||
const session = supabase.auth.session();
|
||||
|
||||
setUser(session?.user);
|
||||
setSession(session);
|
||||
setLoading(false);
|
||||
|
||||
// Listen for changes on auth state (logged in, signed out, etc.)
|
||||
const { data: listener } = supabase.auth.onAuthStateChange(
|
||||
(event, session): void => {
|
||||
if (event === 'SIGNED_OUT' || event === 'SIGNED_IN') {
|
||||
void fetch('/api/auth', {
|
||||
method: 'POST',
|
||||
headers: new Headers({ 'Content-Type': 'application/json' }),
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({ event, session }),
|
||||
}).then((response) => response.json());
|
||||
}
|
||||
setUser(session?.user);
|
||||
setSession(session);
|
||||
setLoading(false);
|
||||
}
|
||||
);
|
||||
|
||||
return () => {
|
||||
listener?.unsubscribe();
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Will be passed down to Signup, Login and Dashboard components
|
||||
const value = {
|
||||
signUp: (data: UserCredentials) => supabase.auth.signUp(data),
|
||||
signIn: (data: UserCredentials) => supabase.auth.signIn(data),
|
||||
signOut: () => supabase.auth.signOut(),
|
||||
resetPassword: (data: string) =>
|
||||
supabase.auth.api.resetPasswordForEmail(data),
|
||||
user,
|
||||
session,
|
||||
};
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={value}>
|
||||
{!loading && children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
// export the useAuth hook
|
||||
export const useAuth = () => useContext(AuthContext);
|
||||
@@ -4,9 +4,9 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
|
||||
export default function initMiddleware(middleware: any) {
|
||||
return (req: NextApiRequest, res: NextApiResponse) =>
|
||||
return (request: NextApiRequest, res: NextApiResponse) =>
|
||||
new Promise((resolve, reject) => {
|
||||
middleware(req, res, (result: any) => {
|
||||
middleware(request, res, (result: any) => {
|
||||
if (result instanceof Error) {
|
||||
return reject(result);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user