2
0

♻️ Add shared eslint config

This commit is contained in:
Baptiste Arnaud
2022-11-21 11:12:43 +01:00
parent e09adf5c64
commit 451ffbcacf
123 changed files with 1151 additions and 1523 deletions

View File

@@ -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',
},
}

View File

@@ -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:*",

View File

@@ -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>
)
})

View File

@@ -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)

View File

@@ -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(() => {

View File

@@ -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'>) =>

View File

@@ -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}
/>
)
})

View File

@@ -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}
/>
)
)
})

View File

@@ -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('')

View File

@@ -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) =>

View File

@@ -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) => {

View File

@@ -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],

View File

@@ -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
}>({})

View File

@@ -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
}>({})

View File

@@ -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
}
}
}

View File

@@ -1,4 +1,4 @@
import { defineConfig } from 'baptistearno-tsup'
import { defineConfig } from 'tsup'
export default defineConfig((options) => ({
entry: ['src/index.ts'],

View File

@@ -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:*"
}
}

View File

@@ -1 +0,0 @@
export { playwrightBaseConfig } from './baseConfig'

View File

@@ -1,6 +0,0 @@
{
"compilerOptions": {
"moduleResolution": "node",
"esModuleInterop": true
}
}

View File

@@ -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"
}
}

View File

@@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: ['custom'],
}

View File

@@ -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",

View File

@@ -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&apos;s amazing. 💙</Text>
<Text>
This means you've almost reached your monthly chats limit. You
currently reached 80% of {readableChatsLimit} chats.
This means you&apos;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&apos;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

View File

@@ -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&apos;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&apos;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&apos;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&apos;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>

View File

@@ -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 &quot;{workspaceName}&quot; 👍
</Text>
<Text>
Make sure to log in as <i>{guestEmail}</i>.

View File

@@ -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&apos;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&apos;d like to continue chatting with your users this
month, then you need to upgrade your plan. 🚀
</Text>
<MjmlSpacer height="24px" />

View File

@@ -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&apos;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&apos;t collect new files from your users
</Text>
<Text>
If you'd like to continue collecting files, then you need to
If you&apos;d like to continue collecting files, then you need to
upgrade your plan or remove existing results to free up space. 🚀
</Text>

View File

@@ -1,6 +1,5 @@
{
"compilerOptions": {
"jsx": "react",
"esModuleInterop": true
}
"extends": "tsconfig/react-library.json",
"include": ["src/**/*"],
"exclude": ["dist", "node_modules"]
}

View 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',
],
},
],
},
}

View 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"
}
}

View File

@@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: ['custom'],
}

View File

@@ -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>

View File

@@ -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'
>

View File

@@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: ['custom'],
}

View File

@@ -13,7 +13,5 @@
"noEmit": true,
"resolveJsonModule": true,
"target": "es5"
},
"include": ["src", "next-env.d.ts"],
"exclude": ["node_modules"]
}
}

View 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"
}
}

View File

@@ -1,2 +0,0 @@
*.js
*.html

View File

@@ -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'],
}

View File

@@ -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:*"
}
}

View File

@@ -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'

View File

@@ -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', () => {

View File

@@ -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"]
}

View File

@@ -1,4 +1,4 @@
import { defineConfig } from 'baptistearno-tsup'
import { defineConfig } from 'tsup'
export default defineConfig((options) => ({
entry: ['src/index.ts'],

View File

@@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: ['custom'],
}

View File

@@ -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",

View File

@@ -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

View File

@@ -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)

View File

@@ -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) => {