♻️ (builder) Change to features-centric folder structure

This commit is contained in:
Baptiste Arnaud
2022-11-15 09:35:48 +01:00
committed by Baptiste Arnaud
parent 3686465a85
commit 643571fe7d
683 changed files with 3907 additions and 3643 deletions

View File

@@ -0,0 +1,52 @@
import { Credentials as CredentialsFromDb } from 'db'
import { OAuth2Client, Credentials } from 'google-auth-library'
import { GoogleSheetsCredentialsData } from 'models'
import { isDefined } from 'utils'
import { decrypt, encrypt } from 'utils/api'
import prisma from './prisma'
export const oauth2Client = new OAuth2Client(
process.env.GOOGLE_CLIENT_ID,
process.env.GOOGLE_CLIENT_SECRET,
`${process.env.NEXTAUTH_URL}/api/credentials/google-sheets/callback`
)
export const getAuthenticatedGoogleClient = async (
userId: string,
credentialsId: string
): Promise<
{ client: OAuth2Client; credentials: CredentialsFromDb } | undefined
> => {
const credentials = (await prisma.credentials.findFirst({
where: { id: credentialsId, workspace: { members: { some: { userId } } } },
})) as CredentialsFromDb | undefined
if (!credentials) return
const data = decrypt(
credentials.data,
credentials.iv
) as GoogleSheetsCredentialsData
oauth2Client.setCredentials(data)
oauth2Client.on('tokens', updateTokens(credentialsId, data))
return { client: oauth2Client, credentials }
}
const updateTokens =
(credentialsId: string, existingCredentials: GoogleSheetsCredentialsData) =>
async (credentials: Credentials) => {
if (
isDefined(existingCredentials.id_token) &&
credentials.id_token !== existingCredentials.id_token
)
return
const newCredentials: GoogleSheetsCredentialsData = {
...existingCredentials,
expiry_date: credentials.expiry_date,
access_token: credentials.access_token,
}
const { encryptedData, iv } = encrypt(newCredentials)
await prisma.credentials.update({
where: { id: credentialsId },
data: { data: encryptedData, iv },
})
}

View File

@@ -0,0 +1,47 @@
import {
createBoldPlugin,
createItalicPlugin,
createUnderlinePlugin,
} from '@udecode/plate-basic-marks'
import { createPlugins } from '@udecode/plate-core'
import { createLinkPlugin, ELEMENT_LINK } from '@udecode/plate-link'
import { PlateFloatingLink } from '@udecode/plate-ui-link'
export const editorStyle: React.CSSProperties = {
flex: 1,
padding: '1rem',
backgroundColor: 'white',
borderRadius: '0.25rem',
}
export const platePlugins = createPlugins(
[
createBoldPlugin(),
createItalicPlugin(),
createUnderlinePlugin(),
createLinkPlugin({
renderAfterEditable: PlateFloatingLink,
options: {
isUrl: (url: string) =>
url.startsWith('http') ||
url.startsWith('mailto') ||
url.startsWith('tel') ||
url.startsWith('sms'),
},
}),
],
{
components: {
[ELEMENT_LINK]: (props) => (
<a
href={props.element.url}
target="_blank"
rel="noreferrer"
className={props.className}
>
{props.children}
</a>
),
},
}
)

View File

@@ -0,0 +1,15 @@
import { PrismaClient } from 'db'
declare const global: { prisma: PrismaClient }
let prisma: PrismaClient
if (process.env.NODE_ENV === 'production') {
prisma = new PrismaClient()
} else {
if (!global.prisma) {
global.prisma = new PrismaClient()
}
prisma = global.prisma
}
export default prisma

View File

@@ -0,0 +1,22 @@
import Router from 'next/router'
import NProgress from 'nprogress'
import { useEffect } from 'react'
export const useRouterProgressBar = () =>
useEffect(() => {
if (typeof window !== 'undefined') {
NProgress.configure({ showSpinner: false })
Router.events.on('routeChangeStart', () => {
NProgress.start()
})
Router.events.on('routeChangeComplete', () => {
NProgress.done()
})
Router.events.on('routeChangeError', () => {
NProgress.done()
})
}
}, [])

View File

@@ -0,0 +1,110 @@
import { extendTheme } from '@chakra-ui/react'
const fonts = {
heading: 'Outfit',
body: 'Open Sans',
}
export const colors = {
gray: {
50: '#F9FAFB',
100: '#F3F4F6',
200: '#E5E7EB',
300: '#D1D5DB',
400: '#9CA3AF',
500: '#6B7280',
600: '#4B5563',
700: '#374151',
800: '#1F2937',
900: '#111827',
},
blue: {
50: '#e0edff',
100: '#b0caff',
200: '#7ea6ff',
300: '#4b83ff',
400: '#1a5fff',
500: '#0042da',
600: '#0036b4',
700: '#002782',
800: '#001751',
900: '#1a202c',
},
orange: {
50: '#fff1da',
100: '#ffd7ae',
200: '#ffbf7d',
300: '#ffa54c',
400: '#ff8b1a',
500: '#e67200',
600: '#b45800',
700: '#813e00',
800: '#4f2500',
900: '#200b00',
},
yellow: {
50: '#fff9da',
100: '#ffedad',
200: '#ffe17d',
300: '#ffd54b',
400: '#ffc91a',
500: '#e6b000',
600: '#b38800',
700: '#806200',
800: '#4e3a00',
900: '#1d1400',
},
}
const components = {
Spinner: {
defaultProps: {
colorScheme: 'blue',
},
},
NumberInput: {
defaultProps: {
focusBorderColor: 'blue.200',
},
},
Input: {
defaultProps: {
focusBorderColor: 'blue.200',
},
},
Textarea: {
defaultProps: {
focusBorderColor: 'blue.200',
},
},
Popover: {
baseStyle: {
popper: {
width: 'fit-content',
maxWidth: 'fit-content',
},
},
},
Link: {
baseStyle: {
_hover: { textDecoration: 'none' },
},
},
Menu: {
parts: ['list'],
defaultProps: {
list: {
shadow: 'lg',
},
},
},
Tooltip: {
defaultProps: {
rounded: 'md',
hasArrow: true,
},
},
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const customTheme: any = extendTheme({ colors, fonts, components })