♻️ Add shared eslint config
This commit is contained in:
@@ -1,48 +1,8 @@
|
||||
module.exports = {
|
||||
ignorePatterns: ['node_modules'],
|
||||
env: {
|
||||
browser: true,
|
||||
es6: true,
|
||||
},
|
||||
extends: [
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:react/recommended',
|
||||
'next/core-web-vitals',
|
||||
'prettier',
|
||||
],
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
|
||||
sourceType: 'module', // Allows for the use of imports
|
||||
ecmaFeatures: {
|
||||
jsx: true, // Allows for the parsing of JSX
|
||||
},
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect', // Tells eslint-plugin-react to automatically detect the version of React to use
|
||||
},
|
||||
},
|
||||
plugins: ['prettier', 'react', '@typescript-eslint'],
|
||||
ignorePatterns: 'dist',
|
||||
root: true,
|
||||
extends: ['custom'],
|
||||
rules: {
|
||||
'react/no-unescaped-entities': [0],
|
||||
'prettier/prettier': 'error',
|
||||
'react/display-name': [0],
|
||||
'@next/next/no-img-element': [0],
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
patterns: [
|
||||
'*/src/*',
|
||||
'src/*',
|
||||
'*/src',
|
||||
'@/features/*/*',
|
||||
'@/index',
|
||||
'!@/features/blocks/*',
|
||||
'!@/features/*/api',
|
||||
],
|
||||
},
|
||||
],
|
||||
'@next/next/no-img-element': 'off',
|
||||
'@next/next/no-html-link-for-pages': 'off',
|
||||
},
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
"module": "dist/index.mjs",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsup",
|
||||
"build": "pnpm tsc --noEmit && tsup",
|
||||
"dev": "tsup --watch",
|
||||
"lint": "eslint --fix -c ./.eslintrc.js \"./src/**/*.ts*\""
|
||||
"lint": "eslint \"src/**/*.ts*\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@stripe/react-stripe-js": "1.15.0",
|
||||
@@ -28,16 +28,11 @@
|
||||
"@types/react-phone-number-input": "3.0.14",
|
||||
"@types/react-scroll": "1.8.5",
|
||||
"@types/react-transition-group": "4.4.5",
|
||||
"@typescript-eslint/eslint-plugin": "5.43.0",
|
||||
"@typescript-eslint/parser": "5.43.0",
|
||||
"autoprefixer": "10.4.13",
|
||||
"baptistearno-tsup": "^0.1.0",
|
||||
"tsup": "6.5.0",
|
||||
"db": "workspace:*",
|
||||
"eslint": "8.27.0",
|
||||
"eslint-config-next": "13.0.3",
|
||||
"eslint-config-prettier": "8.5.0",
|
||||
"eslint-plugin-prettier": "4.2.1",
|
||||
"eslint-plugin-react": "7.31.10",
|
||||
"eslint": "8.28.0",
|
||||
"eslint-config-custom": "workspace:*",
|
||||
"models": "workspace:*",
|
||||
"postcss": "8.4.19",
|
||||
"prettier": "2.7.1",
|
||||
@@ -46,7 +41,8 @@
|
||||
"tailwindcss": "3.2.4",
|
||||
"typescript": "4.8.4",
|
||||
"utils": "workspace:*",
|
||||
"typebot-js": "workspace:*"
|
||||
"typebot-js": "workspace:*",
|
||||
"tsconfig": "workspace:*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"db": "workspace:*",
|
||||
|
||||
@@ -13,59 +13,60 @@ import { ResizeObserver } from 'resize-observer'
|
||||
|
||||
type Props = { hostAvatarSrc?: string; keepShowing: boolean }
|
||||
|
||||
export const AvatarSideContainer = forwardRef(
|
||||
({ hostAvatarSrc, keepShowing }: Props, ref: ForwardedRef<unknown>) => {
|
||||
const { document } = useFrame()
|
||||
const [show, setShow] = useState(false)
|
||||
const [avatarTopOffset, setAvatarTopOffset] = useState(0)
|
||||
export const AvatarSideContainer = forwardRef(function AvatarSideContainer(
|
||||
{ hostAvatarSrc, keepShowing }: Props,
|
||||
ref: ForwardedRef<unknown>
|
||||
) {
|
||||
const { document } = useFrame()
|
||||
const [show, setShow] = useState(false)
|
||||
const [avatarTopOffset, setAvatarTopOffset] = useState(0)
|
||||
|
||||
const refreshTopOffset = () => {
|
||||
if (!scrollingSideGroupRef.current || !avatarContainer.current) return
|
||||
const { height } = scrollingSideGroupRef.current.getBoundingClientRect()
|
||||
const { height: avatarHeight } =
|
||||
avatarContainer.current.getBoundingClientRect()
|
||||
setAvatarTopOffset(height - avatarHeight)
|
||||
}
|
||||
const scrollingSideGroupRef = useRef<HTMLDivElement>(null)
|
||||
const avatarContainer = useRef<HTMLDivElement>(null)
|
||||
useImperativeHandle(ref, () => ({
|
||||
refreshTopOffset,
|
||||
}))
|
||||
|
||||
useEffect(() => {
|
||||
if (!document) return
|
||||
setShow(true)
|
||||
const resizeObserver = new ResizeObserver(refreshTopOffset)
|
||||
resizeObserver.observe(document.body)
|
||||
return () => {
|
||||
resizeObserver.disconnect()
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex w-6 xs:w-10 mr-2 mb-2 flex-shrink-0 items-center relative typebot-avatar-container "
|
||||
ref={scrollingSideGroupRef}
|
||||
>
|
||||
<CSSTransition
|
||||
classNames="bubble"
|
||||
timeout={500}
|
||||
in={show && keepShowing}
|
||||
unmountOnExit
|
||||
>
|
||||
<div
|
||||
className="absolute w-6 xs:w-10 h-6 xs:h-10 mb-4 xs:mb-2 flex items-center top-0"
|
||||
ref={avatarContainer}
|
||||
style={{
|
||||
top: `${avatarTopOffset}px`,
|
||||
transition: 'top 350ms ease-out, opacity 500ms',
|
||||
}}
|
||||
>
|
||||
<Avatar avatarSrc={hostAvatarSrc} />
|
||||
</div>
|
||||
</CSSTransition>
|
||||
</div>
|
||||
)
|
||||
const refreshTopOffset = () => {
|
||||
if (!scrollingSideGroupRef.current || !avatarContainer.current) return
|
||||
const { height } = scrollingSideGroupRef.current.getBoundingClientRect()
|
||||
const { height: avatarHeight } =
|
||||
avatarContainer.current.getBoundingClientRect()
|
||||
setAvatarTopOffset(height - avatarHeight)
|
||||
}
|
||||
)
|
||||
const scrollingSideGroupRef = useRef<HTMLDivElement>(null)
|
||||
const avatarContainer = useRef<HTMLDivElement>(null)
|
||||
useImperativeHandle(ref, () => ({
|
||||
refreshTopOffset,
|
||||
}))
|
||||
|
||||
useEffect(() => {
|
||||
if (!document) return
|
||||
setShow(true)
|
||||
const resizeObserver = new ResizeObserver(refreshTopOffset)
|
||||
resizeObserver.observe(document.body)
|
||||
return () => {
|
||||
resizeObserver.disconnect()
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex w-6 xs:w-10 mr-2 mb-2 flex-shrink-0 items-center relative typebot-avatar-container "
|
||||
ref={scrollingSideGroupRef}
|
||||
>
|
||||
<CSSTransition
|
||||
classNames="bubble"
|
||||
timeout={500}
|
||||
in={show && keepShowing}
|
||||
unmountOnExit
|
||||
>
|
||||
<div
|
||||
className="absolute w-6 xs:w-10 h-6 xs:h-10 mb-4 xs:mb-2 flex items-center top-0"
|
||||
ref={avatarContainer}
|
||||
style={{
|
||||
top: `${avatarTopOffset}px`,
|
||||
transition: 'top 350ms ease-out, opacity 500ms',
|
||||
}}
|
||||
>
|
||||
<Avatar avatarSrc={hostAvatarSrc} />
|
||||
</div>
|
||||
</CSSTransition>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
@@ -53,7 +53,7 @@ export const InputChatBlock = ({
|
||||
blockId: block.id,
|
||||
groupId: block.groupId,
|
||||
content: value,
|
||||
variableId: variableId ?? null,
|
||||
variableId,
|
||||
uploadedFiles: block.type === InputBlockType.FILE,
|
||||
})
|
||||
if (!isEditting) onTransitionEnd({ label, value, itemId }, isRetry)
|
||||
|
||||
@@ -246,7 +246,6 @@ const ChatChunks = ({
|
||||
}: Props) => {
|
||||
const [isSkipped, setIsSkipped] = useState(false)
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const avatarSideContainerRef = useRef<any>()
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -8,6 +8,7 @@ import { ConversationContainer } from './ConversationContainer'
|
||||
import { AnswersProvider } from '../providers/AnswersProvider'
|
||||
import {
|
||||
Answer,
|
||||
AnswerInput,
|
||||
BackgroundType,
|
||||
Edge,
|
||||
PublicTypebot,
|
||||
@@ -27,7 +28,9 @@ export type TypebotViewerProps = {
|
||||
startGroupId?: string
|
||||
isLoading?: boolean
|
||||
onNewGroupVisible?: (edge: Edge) => void
|
||||
onNewAnswer?: (answer: Answer & { uploadedFiles: boolean }) => Promise<void>
|
||||
onNewAnswer?: (
|
||||
answer: AnswerInput & { uploadedFiles: boolean }
|
||||
) => Promise<void>
|
||||
onNewLog?: (log: Omit<Log, 'id' | 'createdAt' | 'resultId'>) => void
|
||||
onCompleted?: () => void
|
||||
onVariablesUpdated?: (variables: VariableWithValue[]) => void
|
||||
@@ -58,7 +61,7 @@ export const TypebotViewer = ({
|
||||
const handleNewGroupVisible = (edge: Edge) =>
|
||||
onNewGroupVisible && onNewGroupVisible(edge)
|
||||
|
||||
const handleNewAnswer = (answer: Answer & { uploadedFiles: boolean }) =>
|
||||
const handleNewAnswer = (answer: AnswerInput & { uploadedFiles: boolean }) =>
|
||||
onNewAnswer && onNewAnswer(answer)
|
||||
|
||||
const handleNewLog = (log: Omit<Log, 'id' | 'createdAt' | 'resultId'>) =>
|
||||
|
||||
@@ -5,21 +5,19 @@ type ShortTextInputProps = {
|
||||
onChange: (value: string) => void
|
||||
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'>
|
||||
|
||||
export const ShortTextInput = React.forwardRef(
|
||||
(
|
||||
{ onChange, ...props }: ShortTextInputProps,
|
||||
ref: React.ForwardedRef<HTMLInputElement>
|
||||
) => {
|
||||
return (
|
||||
<input
|
||||
ref={ref}
|
||||
className="focus:outline-none bg-transparent px-4 py-4 flex-1 w-full text-input"
|
||||
type="text"
|
||||
style={{ fontSize: '16px' }}
|
||||
autoFocus={!isMobile}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
export const ShortTextInput = React.forwardRef(function ShortTextInput(
|
||||
{ onChange, ...props }: ShortTextInputProps,
|
||||
ref: React.ForwardedRef<HTMLInputElement>
|
||||
) {
|
||||
return (
|
||||
<input
|
||||
ref={ref}
|
||||
className="focus:outline-none bg-transparent px-4 py-4 flex-1 w-full text-input"
|
||||
type="text"
|
||||
style={{ fontSize: '16px' }}
|
||||
autoFocus={!isMobile}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
||||
@@ -5,11 +5,11 @@ type TextareaProps = {
|
||||
onChange: (value: string) => void
|
||||
} & Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'onChange'>
|
||||
|
||||
export const Textarea = React.forwardRef(
|
||||
(
|
||||
{ onChange, ...props }: TextareaProps,
|
||||
ref: React.ForwardedRef<HTMLTextAreaElement>
|
||||
) => (
|
||||
export const Textarea = React.forwardRef(function Textarea(
|
||||
{ onChange, ...props }: TextareaProps,
|
||||
ref: React.ForwardedRef<HTMLTextAreaElement>
|
||||
) {
|
||||
return (
|
||||
<textarea
|
||||
ref={ref}
|
||||
className="focus:outline-none bg-transparent px-4 py-4 flex-1 w-full text-input"
|
||||
@@ -22,4 +22,4 @@ export const Textarea = React.forwardRef(
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
@@ -9,6 +9,7 @@ import { parseVariables } from '@/features/variables'
|
||||
import { useChat } from '@/providers/ChatProvider'
|
||||
import { useTypebot } from '@/providers/TypebotProvider'
|
||||
import { createPaymentIntentQuery } from '../../queries/createPaymentIntentQuery'
|
||||
import { Stripe } from '@stripe/stripe-js'
|
||||
|
||||
type Props = {
|
||||
options: PaymentInputOptions
|
||||
@@ -23,8 +24,7 @@ export const StripePaymentForm = ({ options, onSuccess }: Props) => {
|
||||
onNewLog,
|
||||
} = useTypebot()
|
||||
const { window: frameWindow, document: frameDocument } = useFrame()
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const [stripe, setStripe] = useState<any>(null)
|
||||
const [stripe, setStripe] = useState<Stripe | null>(null)
|
||||
const [clientSecret, setClientSecret] = useState('')
|
||||
const [amountLabel, setAmountLabel] = useState('')
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ export const PhoneInput = ({
|
||||
hasGuestAvatar,
|
||||
}: PhoneInputProps) => {
|
||||
const [inputValue, setInputValue] = useState(defaultValue ?? '')
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const inputRef = useRef<any>(null)
|
||||
|
||||
const handleChange = (inputValue: Value | undefined) =>
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import { GoogleAnalyticsOptions } from 'models'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
declare const gtag: any
|
||||
declare const gtag: (
|
||||
type: string,
|
||||
action: string | undefined,
|
||||
options: {
|
||||
event_category: string | undefined
|
||||
event_label: string | undefined
|
||||
value: number | undefined
|
||||
}
|
||||
) => void
|
||||
|
||||
const initGoogleAnalytics = (id: string): Promise<void> =>
|
||||
new Promise((resolve) => {
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { safeStringify } from '@/features/variables'
|
||||
import {
|
||||
Answer,
|
||||
AnswerInput,
|
||||
ResultValues,
|
||||
VariableWithUnknowValue,
|
||||
VariableWithValue,
|
||||
} from 'models'
|
||||
import React, { createContext, ReactNode, useContext, useState } from 'react'
|
||||
import { createContext, ReactNode, useContext, useState } from 'react'
|
||||
|
||||
const answersContext = createContext<{
|
||||
resultId?: string
|
||||
resultValues: ResultValues
|
||||
addAnswer: (
|
||||
answer: Answer & { uploadedFiles: boolean }
|
||||
answer: AnswerInput & { uploadedFiles: boolean }
|
||||
) => Promise<void> | undefined
|
||||
updateVariables: (variables: VariableWithUnknowValue[]) => void
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
//@ts-ignore
|
||||
}>({})
|
||||
|
||||
@@ -26,7 +26,7 @@ export const AnswersProvider = ({
|
||||
}: {
|
||||
resultId?: string
|
||||
onNewAnswer: (
|
||||
answer: Answer & { uploadedFiles: boolean }
|
||||
answer: AnswerInput & { uploadedFiles: boolean }
|
||||
) => Promise<void> | undefined
|
||||
onVariablesUpdated?: (variables: VariableWithValue[]) => void
|
||||
children: ReactNode
|
||||
@@ -34,10 +34,10 @@ export const AnswersProvider = ({
|
||||
const [resultValues, setResultValues] = useState<ResultValues>({
|
||||
answers: [],
|
||||
variables: [],
|
||||
createdAt: new Date().toISOString(),
|
||||
createdAt: new Date(),
|
||||
})
|
||||
|
||||
const addAnswer = (answer: Answer & { uploadedFiles: boolean }) => {
|
||||
const addAnswer = (answer: AnswerInput & { uploadedFiles: boolean }) => {
|
||||
setResultValues((resultValues) => ({
|
||||
...resultValues,
|
||||
answers: [...resultValues.answers, answer],
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { createContext, ReactNode, useContext } from 'react'
|
||||
|
||||
const chatContext = createContext<{
|
||||
scroll: () => void
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
//@ts-ignore
|
||||
}>({})
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ const typebotContext = createContext<{
|
||||
edgeId: string
|
||||
}) => void
|
||||
onNewLog: (log: Omit<Log, 'id' | 'createdAt' | 'resultId'>) => void
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
//@ts-ignore
|
||||
}>({})
|
||||
|
||||
|
||||
@@ -1,24 +1,10 @@
|
||||
{
|
||||
"extends": "tsconfig/react-library.json",
|
||||
"include": ["src/**/*"],
|
||||
"compilerOptions": {
|
||||
"lib": ["ES2017", "DOM"],
|
||||
"target": "es5",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"jsx": "react",
|
||||
"module": "ESNext",
|
||||
"declaration": true,
|
||||
"declarationDir": "types",
|
||||
"sourceMap": true,
|
||||
"outDir": "dist",
|
||||
"moduleResolution": "node",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
},
|
||||
"downlevelIteration": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineConfig } from 'baptistearno-tsup'
|
||||
import { defineConfig } from 'tsup'
|
||||
|
||||
export default defineConfig((options) => ({
|
||||
entry: ['src/index.ts'],
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"name": "configs",
|
||||
"version": "1.0.0",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@playwright/test": "1.27.1",
|
||||
"@types/node": "18.11.9",
|
||||
"dotenv": "16.0.3",
|
||||
"utils": "workspace:*"
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { playwrightBaseConfig } from './baseConfig'
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true
|
||||
}
|
||||
}
|
||||
@@ -19,9 +19,9 @@
|
||||
"@prisma/client": "4.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prisma": "4.6.1",
|
||||
"typescript": "4.8.4",
|
||||
"dotenv-cli": "6.0.0",
|
||||
"tsconfig": "workspace:*"
|
||||
"prisma": "4.6.1",
|
||||
"tsconfig": "workspace:*",
|
||||
"typescript": "4.8.4"
|
||||
}
|
||||
}
|
||||
|
||||
4
packages/emails/.eslintrc.js
Normal file
4
packages/emails/.eslintrc.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ['custom'],
|
||||
}
|
||||
@@ -2,12 +2,13 @@
|
||||
"name": "emails",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "./index.ts",
|
||||
"types": "./index.ts",
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"scripts": {
|
||||
"preview": "concurrently \"pnpm run watch\" \"sleep 5 && pnpm run serve\" -n \"watch,serve\" -c \"bgBlue.bold,bgMagenta.bold\"",
|
||||
"watch": "tsx watch ./preview.tsx --clear-screen=false",
|
||||
"serve": "http-server dist -a localhost -p 3223 -o"
|
||||
"serve": "http-server dist -a localhost -p 3223 -o",
|
||||
"lint": "eslint \"src/**/*.ts*\""
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Baptiste Arnaud",
|
||||
@@ -22,7 +23,10 @@
|
||||
"nodemailer": "6.8.0",
|
||||
"react": "18.2.0",
|
||||
"tsx": "3.12.1",
|
||||
"utils": "workspace:*"
|
||||
"utils": "workspace:*",
|
||||
"eslint": "8.28.0",
|
||||
"eslint-config-custom": "workspace:*",
|
||||
"tsconfig": "workspace:*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@faire/mjml-react": "2.1.4",
|
||||
|
||||
@@ -42,15 +42,15 @@ export const AlmostReachedChatsLimitEmail = ({
|
||||
</MjmlSection>
|
||||
<MjmlSection padding="0 24px" cssClass="smooth">
|
||||
<MjmlColumn>
|
||||
<Text>Your bots are chatting a lot. That's amazing. 💙</Text>
|
||||
<Text>Your bots are chatting a lot. That's amazing. 💙</Text>
|
||||
<Text>
|
||||
This means you've almost reached your monthly chats limit. You
|
||||
currently reached 80% of {readableChatsLimit} chats.
|
||||
This means you've almost reached your monthly chats limit.
|
||||
You currently reached 80% of {readableChatsLimit} chats.
|
||||
</Text>
|
||||
<Text>This limit will be reset on {readableResetDate}.</Text>
|
||||
<Text fontWeight={800}>
|
||||
Your bots won't start the chat if you reach the limit before this
|
||||
date❗
|
||||
Your bots won't start the chat if you reach the limit before
|
||||
this date❗
|
||||
</Text>
|
||||
<Text>
|
||||
If you need more monthly responses, you will need to upgrade your
|
||||
@@ -33,17 +33,18 @@ export const AlmostReachedStorageLimitEmail = ({
|
||||
</MjmlSection>
|
||||
<MjmlSection padding="0 24px" cssClass="smooth">
|
||||
<MjmlColumn>
|
||||
<Text>Your bots are working a lot. That's amazing. 🤖</Text>
|
||||
<Text>Your bots are working a lot. That's amazing. 🤖</Text>
|
||||
<Text>
|
||||
This means you've almost reached your storage limit. You currently
|
||||
reached 80% of your {readableStorageLimit} storage limit.
|
||||
This means you've almost reached your storage limit. You
|
||||
currently reached 80% of your {readableStorageLimit} storage
|
||||
limit.
|
||||
</Text>
|
||||
<Text fontWeight={800}>
|
||||
Your bots won't collect new files once you reach the limit❗
|
||||
Your bots won't collect new files once you reach the limit❗
|
||||
</Text>
|
||||
<Text>
|
||||
To make sure it won't happen, you need to upgrade your plan or
|
||||
delete existing results to free up space.
|
||||
To make sure it won't happen, you need to upgrade your plan
|
||||
or delete existing results to free up space.
|
||||
</Text>
|
||||
<MjmlSpacer height="24px" />
|
||||
<Button link={url}>Upgrade workspace</Button>
|
||||
@@ -42,7 +42,7 @@ export const GuestInvitationEmail = ({
|
||||
</Text>
|
||||
<Text>
|
||||
From now on you will see this typebot in your dashboard under his
|
||||
workspace "{workspaceName}" 👍
|
||||
workspace "{workspaceName}" 👍
|
||||
</Text>
|
||||
<Text>
|
||||
Make sure to log in as <i>{guestEmail}</i>.
|
||||
@@ -43,15 +43,15 @@ export const ReachedChatsLimitEmail = ({
|
||||
<MjmlSection padding="0 24px" cssClass="smooth">
|
||||
<MjmlColumn>
|
||||
<Text>
|
||||
It just happened, you've reached your monthly {readableChatsLimit}{' '}
|
||||
chats limit 😮
|
||||
It just happened, you've reached your monthly{' '}
|
||||
{readableChatsLimit} chats limit 😮
|
||||
</Text>
|
||||
<Text fontWeight={800}>
|
||||
It means your bots are closed until {readableResetDate}❗
|
||||
</Text>
|
||||
<Text>
|
||||
If you'd like to continue chatting with your users this month,
|
||||
then you need to upgrade your plan. 🚀
|
||||
If you'd like to continue chatting with your users this
|
||||
month, then you need to upgrade your plan. 🚀
|
||||
</Text>
|
||||
|
||||
<MjmlSpacer height="24px" />
|
||||
@@ -34,14 +34,14 @@ export const ReachedStorageLimitEmail = ({
|
||||
<MjmlSection padding="0 24px" cssClass="smooth">
|
||||
<MjmlColumn>
|
||||
<Text>
|
||||
It just happened, you've reached your {readableStorageLimit}{' '}
|
||||
It just happened, you've reached your {readableStorageLimit}{' '}
|
||||
storage limit 😮
|
||||
</Text>
|
||||
<Text fontWeight={800}>
|
||||
It means your bots won't collect new files from your users❗
|
||||
It means your bots won't collect new files from your users❗
|
||||
</Text>
|
||||
<Text>
|
||||
If you'd like to continue collecting files, then you need to
|
||||
If you'd like to continue collecting files, then you need to
|
||||
upgrade your plan or remove existing results to free up space. 🚀
|
||||
</Text>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"jsx": "react",
|
||||
"esModuleInterop": true
|
||||
}
|
||||
"extends": "tsconfig/react-library.json",
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["dist", "node_modules"]
|
||||
}
|
||||
|
||||
23
packages/eslint-config-custom/index.js
Normal file
23
packages/eslint-config-custom/index.js
Normal file
@@ -0,0 +1,23 @@
|
||||
module.exports = {
|
||||
extends: ['next', 'prettier'],
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect',
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
patterns: [
|
||||
'*/src/*',
|
||||
'src/*',
|
||||
'*/src',
|
||||
'@/features/*/*',
|
||||
'!@/features/blocks/*',
|
||||
'!@/features/*/api',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
10
packages/eslint-config-custom/package.json
Normal file
10
packages/eslint-config-custom/package.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "eslint-config-custom",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"eslint": "8.28.0",
|
||||
"eslint-config-next": "13.0.4",
|
||||
"eslint-config-prettier": "8.5.0",
|
||||
"eslint-plugin-react": "7.31.11"
|
||||
}
|
||||
}
|
||||
4
packages/models/.eslintrc.js
Normal file
4
packages/models/.eslintrc.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ['custom'],
|
||||
}
|
||||
@@ -10,6 +10,20 @@ export const answerSchema = z.object({
|
||||
storageUsed: z.number().nullable(),
|
||||
})
|
||||
|
||||
export const answerInputSchema = answerSchema
|
||||
.omit({
|
||||
createdAt: true,
|
||||
resultId: true,
|
||||
variableId: true,
|
||||
storageUsed: true,
|
||||
})
|
||||
.and(
|
||||
z.object({
|
||||
variableId: z.string().nullish(),
|
||||
storageUsed: z.number().nullish(),
|
||||
})
|
||||
)
|
||||
|
||||
export type Stats = {
|
||||
totalViews: number
|
||||
totalStarts: number
|
||||
@@ -17,3 +31,5 @@ export type Stats = {
|
||||
}
|
||||
|
||||
export type Answer = z.infer<typeof answerSchema>
|
||||
|
||||
export type AnswerInput = z.infer<typeof answerInputSchema>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { z } from 'zod'
|
||||
import { answerSchema } from './answer'
|
||||
import { answerInputSchema, answerSchema } from './answer'
|
||||
import { InputBlockType } from './blocks'
|
||||
import { variableWithValueSchema } from './typebot/variable'
|
||||
|
||||
@@ -20,6 +20,12 @@ export const resultWithAnswersSchema = resultSchema.and(
|
||||
})
|
||||
)
|
||||
|
||||
export const resultWithAnswersInputSchema = resultSchema.and(
|
||||
z.object({
|
||||
answers: z.array(answerInputSchema),
|
||||
})
|
||||
)
|
||||
|
||||
export const logSchema = z.object({
|
||||
id: z.string(),
|
||||
createdAt: z.date(),
|
||||
@@ -33,10 +39,14 @@ export type Result = z.infer<typeof resultSchema>
|
||||
|
||||
export type ResultWithAnswers = z.infer<typeof resultWithAnswersSchema>
|
||||
|
||||
export type ResultWithAnswersInput = z.infer<
|
||||
typeof resultWithAnswersInputSchema
|
||||
>
|
||||
|
||||
export type Log = z.infer<typeof logSchema>
|
||||
|
||||
export type ResultValues = Pick<
|
||||
ResultWithAnswers,
|
||||
ResultWithAnswersInput,
|
||||
'answers' | 'createdAt' | 'variables'
|
||||
>
|
||||
|
||||
|
||||
4
packages/scripts/.eslintrc.js
Normal file
4
packages/scripts/.eslintrc.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ['custom'],
|
||||
}
|
||||
@@ -13,7 +13,5 @@
|
||||
"noEmit": true,
|
||||
"resolveJsonModule": true,
|
||||
"target": "es5"
|
||||
},
|
||||
"include": ["src", "next-env.d.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
}
|
||||
|
||||
11
packages/tsconfig/react-library.json
Normal file
11
packages/tsconfig/react-library.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"display": "React Library",
|
||||
"extends": "./base.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"lib": ["ES2015", "dom", "dom.iterable"],
|
||||
"module": "ESNext",
|
||||
"target": "es6"
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
*.js
|
||||
*.html
|
||||
@@ -1,12 +1,5 @@
|
||||
module.exports = {
|
||||
parser: "@typescript-eslint/parser",
|
||||
plugins: ["@typescript-eslint", "prettier"],
|
||||
extends: [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
],
|
||||
rules: {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["off"],
|
||||
},
|
||||
};
|
||||
root: true,
|
||||
extends: ['custom'],
|
||||
ignorePatterns: ['/tests'],
|
||||
}
|
||||
|
||||
@@ -7,22 +7,19 @@
|
||||
"scripts": {
|
||||
"dev": "tsup --watch",
|
||||
"build": "tsup",
|
||||
"lint": "eslint src --ext .ts && eslint tests --ext .ts",
|
||||
"lint": "eslint \"src/**/*.ts*\"",
|
||||
"test": "pnpm jest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "29.2.3",
|
||||
"@typescript-eslint/eslint-plugin": "5.43.0",
|
||||
"@typescript-eslint/parser": "5.43.0",
|
||||
"baptistearno-tsup": "^0.1.0",
|
||||
"eslint": "8.27.0",
|
||||
"eslint-plugin-functional": "4.4.1",
|
||||
"eslint-plugin-jest": "27.1.5",
|
||||
"eslint-plugin-prettier": "4.2.1",
|
||||
"tsup": "6.5.0",
|
||||
"eslint": "8.28.0",
|
||||
"eslint-config-custom": "workspace:*",
|
||||
"jest": "29.3.1",
|
||||
"jest-environment-jsdom": "29.3.1",
|
||||
"prettier": "2.7.1",
|
||||
"ts-jest": "29.0.3",
|
||||
"typescript": "4.8.4"
|
||||
"typescript": "4.8.4",
|
||||
"tsconfig": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ export {
|
||||
hideMessage,
|
||||
}
|
||||
|
||||
export default {
|
||||
const defaultExports = {
|
||||
initContainer,
|
||||
initPopup,
|
||||
initBubble,
|
||||
@@ -29,4 +29,6 @@ export default {
|
||||
hideMessage,
|
||||
}
|
||||
|
||||
export default defaultExports
|
||||
|
||||
export * from './types'
|
||||
|
||||
@@ -3,11 +3,9 @@ import { initContainer } from '../src/embedTypes/container'
|
||||
const observe = jest.fn()
|
||||
const unobserve = jest.fn()
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
window.IntersectionObserver = jest.fn(() => ({
|
||||
observe,
|
||||
unobserve,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
})) as any
|
||||
|
||||
describe('initContainer', () => {
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"moduleResolution": "Node",
|
||||
"declarationDir": ".",
|
||||
"strict": true
|
||||
},
|
||||
"include": ["./src/**/*.ts"],
|
||||
"exclude": ["./tests/**/*"]
|
||||
"extends": "tsconfig/base.json",
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["dist", "node_modules"]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineConfig } from 'baptistearno-tsup'
|
||||
import { defineConfig } from 'tsup'
|
||||
|
||||
export default defineConfig((options) => ({
|
||||
entry: ['src/index.ts'],
|
||||
|
||||
4
packages/utils/.eslintrc.js
Normal file
4
packages/utils/.eslintrc.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ['custom'],
|
||||
}
|
||||
@@ -11,11 +11,12 @@
|
||||
"aws-sdk": "2.1254.0",
|
||||
"cuid": "2.1.8",
|
||||
"db": "workspace:*",
|
||||
"dotenv": "16.0.3",
|
||||
"models": "workspace:*",
|
||||
"next": "13.0.3",
|
||||
"nodemailer": "6.8.0",
|
||||
"typescript": "4.8.4",
|
||||
"tsconfig": "workspace:*"
|
||||
"tsconfig": "workspace:*",
|
||||
"typescript": "4.8.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"aws-sdk": "2.1152.0",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { FullConfig } from '@playwright/test'
|
||||
import { setupDatabase, teardownDatabase } from 'utils/playwright/databaseSetup'
|
||||
import { setupDatabase, teardownDatabase } from './databaseSetup'
|
||||
|
||||
async function globalSetup(config: FullConfig) {
|
||||
const { baseURL } = config.projects[0].use
|
||||
@@ -169,7 +169,7 @@ const europeanUnionExclusiveLanguageCodes = [
|
||||
]
|
||||
|
||||
export const guessIfUserIsEuropean = () =>
|
||||
navigator.languages.some((language) => {
|
||||
window.navigator.languages.some((language) => {
|
||||
const [languageCode, countryCode] = language.split('-')
|
||||
return countryCode
|
||||
? europeanUnionCountryCodes.includes(countryCode)
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
Answer,
|
||||
VariableWithValue,
|
||||
Typebot,
|
||||
ResultWithAnswersInput,
|
||||
} from 'models'
|
||||
import { isInputBlock, isDefined, byId } from './utils'
|
||||
|
||||
@@ -177,14 +178,16 @@ export const parseAnswers =
|
||||
createdAt,
|
||||
answers,
|
||||
variables: resultVariables,
|
||||
}: Pick<ResultWithAnswers, 'answers' | 'variables'> & {
|
||||
createdAt: string
|
||||
}: Pick<ResultWithAnswersInput, 'answers' | 'variables'> & {
|
||||
// TODO: remove once we are using 100% tRPC
|
||||
createdAt: Date | string
|
||||
}): {
|
||||
[key: string]: string
|
||||
} => {
|
||||
const header = parseResultHeader(typebot, linkedTypebots)
|
||||
return {
|
||||
submittedAt: createdAt,
|
||||
submittedAt:
|
||||
typeof createdAt === 'string' ? createdAt : createdAt.toISOString(),
|
||||
...[...answers, ...resultVariables].reduce<{
|
||||
[key: string]: string
|
||||
}>((o, answerOrVariable) => {
|
||||
|
||||
Reference in New Issue
Block a user