mirror of
https://github.com/formbricks/formbricks.git
synced 2026-02-14 19:08:55 -06:00
chore: improve button a11y with storybook (#2938)
This commit is contained in:
@@ -13,8 +13,8 @@
|
||||
"dependencies": {
|
||||
"@formbricks/js": "workspace:*",
|
||||
"@formbricks/ui": "workspace:*",
|
||||
"lucide-react": "^0.397.0",
|
||||
"next": "14.2.4",
|
||||
"lucide-react": "^0.418.0",
|
||||
"next": "14.2.5",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1"
|
||||
},
|
||||
|
||||
@@ -12,34 +12,34 @@
|
||||
},
|
||||
"browserslist": "defaults, not ie <= 11",
|
||||
"dependencies": {
|
||||
"@algolia/autocomplete-core": "^1.17.2",
|
||||
"@algolia/autocomplete-core": "^1.17.4",
|
||||
"@calcom/embed-react": "^1.5.0",
|
||||
"@docsearch/css": "3",
|
||||
"@docsearch/react": "^3.6.0",
|
||||
"@docsearch/react": "^3.6.1",
|
||||
"@formbricks/lib": "workspace:*",
|
||||
"@formbricks/types": "workspace:*",
|
||||
"@formbricks/ui": "workspace:*",
|
||||
"@headlessui/react": "^2.1.1",
|
||||
"@headlessui/react": "^2.1.2",
|
||||
"@headlessui/tailwindcss": "^0.2.1",
|
||||
"@mapbox/rehype-prism": "^0.9.0",
|
||||
"@mdx-js/loader": "^3.0.1",
|
||||
"@mdx-js/react": "^3.0.1",
|
||||
"@next/mdx": "14.2.4",
|
||||
"@next/mdx": "14.2.5",
|
||||
"@paralleldrive/cuid2": "^2.2.2",
|
||||
"@sindresorhus/slugify": "^2.2.1",
|
||||
"@tailwindcss/typography": "^0.5.13",
|
||||
"acorn": "^8.12.0",
|
||||
"acorn": "^8.12.1",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"clsx": "^2.1.1",
|
||||
"fast-glob": "^3.3.2",
|
||||
"flexsearch": "^0.7.43",
|
||||
"framer-motion": "11.2.12",
|
||||
"framer-motion": "11.3.20",
|
||||
"lottie-web": "^5.12.2",
|
||||
"lucide": "^0.397.0",
|
||||
"lucide-react": "^0.397.0",
|
||||
"lucide": "^0.418.0",
|
||||
"lucide-react": "^0.418.0",
|
||||
"mdast-util-to-string": "^4.0.0",
|
||||
"mdx-annotations": "^0.1.4",
|
||||
"next": "14.2.4",
|
||||
"next": "14.2.5",
|
||||
"next-plausible": "^3.12.0",
|
||||
"next-seo": "^6.5.0",
|
||||
"next-sitemap": "^4.2.3",
|
||||
@@ -59,7 +59,7 @@
|
||||
"sharp": "^0.33.4",
|
||||
"shiki": "^0.14.7",
|
||||
"simple-functional-loader": "^1.2.1",
|
||||
"tailwindcss": "^3.4.4",
|
||||
"tailwindcss": "^3.4.7",
|
||||
"unist-util-filter": "^5.0.1",
|
||||
"unist-util-visit": "^5.0.0",
|
||||
"zustand": "^4.5.4"
|
||||
|
||||
@@ -21,6 +21,7 @@ const config: StorybookConfig = {
|
||||
getAbsolutePath("@storybook/addon-essentials"),
|
||||
getAbsolutePath("@chromatic-com/storybook"),
|
||||
getAbsolutePath("@storybook/addon-interactions"),
|
||||
getAbsolutePath("@storybook/addon-a11y"),
|
||||
],
|
||||
framework: {
|
||||
name: getAbsolutePath("@storybook/react-vite"),
|
||||
|
||||
@@ -12,29 +12,30 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@formbricks/ui": "workspace:*",
|
||||
"eslint-plugin-react-refresh": "^0.4.7",
|
||||
"eslint-plugin-react-refresh": "^0.4.9",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@chromatic-com/storybook": "^1.5.0",
|
||||
"@chromatic-com/storybook": "^1.6.1",
|
||||
"@formbricks/config-typescript": "workspace:*",
|
||||
"@storybook/addon-essentials": "^8.1.10",
|
||||
"@storybook/addon-interactions": "^8.1.10",
|
||||
"@storybook/addon-links": "^8.1.10",
|
||||
"@storybook/addon-onboarding": "^8.1.10",
|
||||
"@storybook/blocks": "^8.1.10",
|
||||
"@storybook/react": "^8.1.10",
|
||||
"@storybook/react-vite": "^8.1.10",
|
||||
"@storybook/test": "^8.1.10",
|
||||
"@typescript-eslint/eslint-plugin": "^7.13.1",
|
||||
"@typescript-eslint/parser": "^7.13.1",
|
||||
"@storybook/addon-a11y": "^8.2.7",
|
||||
"@storybook/addon-essentials": "^8.2.7",
|
||||
"@storybook/addon-interactions": "^8.2.7",
|
||||
"@storybook/addon-links": "^8.2.7",
|
||||
"@storybook/addon-onboarding": "^8.2.7",
|
||||
"@storybook/blocks": "^8.2.7",
|
||||
"@storybook/react": "^8.2.7",
|
||||
"@storybook/react-vite": "^8.2.7",
|
||||
"@storybook/test": "^8.2.7",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"@vitejs/plugin-react": "^4.3.1",
|
||||
"esbuild": "^0.21.5",
|
||||
"esbuild": "^0.23.0",
|
||||
"eslint-plugin-storybook": "^0.8.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"storybook": "^8.1.10",
|
||||
"tsup": "^8.1.0",
|
||||
"vite": "^5.3.1"
|
||||
"storybook": "^8.2.7",
|
||||
"tsup": "^8.2.3",
|
||||
"vite": "^5.3.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ export const ConnectWithFormbricks = ({
|
||||
<Button
|
||||
id="finishOnboarding"
|
||||
className="text-slate-400 hover:text-slate-700"
|
||||
variant={widgetSetupCompleted ? "darkCTA" : "minimal"}
|
||||
variant={widgetSetupCompleted ? "primary" : "minimal"}
|
||||
onClick={handleFinishOnboarding}
|
||||
EndIcon={ArrowRight}>
|
||||
{widgetSetupCompleted ? "Finish Onboarding" : "I don't know how to do it"}
|
||||
|
||||
@@ -105,11 +105,7 @@ export const InviteOrganizationMember = ({ organization, environmentId }: Invite
|
||||
}}>
|
||||
Not now
|
||||
</Button>
|
||||
<Button
|
||||
id="onboarding-inapp-invite-send-invite"
|
||||
variant="darkCTA"
|
||||
type={"submit"}
|
||||
loading={isSubmitting}>
|
||||
<Button id="onboarding-inapp-invite-send-invite" type={"submit"} loading={isSubmitting}>
|
||||
Invite
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -136,7 +136,7 @@ export const OnboardingSetupInstructions = ({
|
||||
<div className="mt-4 flex justify-between space-x-2">
|
||||
<Button
|
||||
id="onboarding-inapp-connect-copy-code"
|
||||
variant={widgetSetupCompleted ? "secondary" : "darkCTA"}
|
||||
variant={widgetSetupCompleted ? "secondary" : "primary"}
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(
|
||||
channel === "app" ? htmlSnippetForAppSurveys : htmlSnippetForWebsiteSurveys
|
||||
|
||||
@@ -140,7 +140,7 @@ export const ProductSettings = ({
|
||||
/>
|
||||
|
||||
<div className="flex w-full justify-end">
|
||||
<Button variant="darkCTA" loading={isSubmitting} type="submit">
|
||||
<Button loading={isSubmitting} type="submit">
|
||||
Next
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -249,7 +249,7 @@ export const CreateNewActionTab = ({
|
||||
<Button type="button" variant="minimal" onClick={resetAllStates}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button variant="darkCTA" type="submit" loading={isSubmitting}>
|
||||
<Button type="submit" loading={isSubmitting}>
|
||||
Create action
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -224,7 +224,7 @@ export const QuestionMenu = ({
|
||||
text="Changing the question type will remove the logic conditions from this question"
|
||||
buttonText="Change anyway"
|
||||
onConfirm={onConfirm}
|
||||
buttonVariant="darkCTA"
|
||||
buttonVariant="primary"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -317,7 +317,6 @@ export const SurveyMenuBar = ({
|
||||
{localSurvey.status !== "draft" && (
|
||||
<Button
|
||||
disabled={disableSave}
|
||||
variant="darkCTA"
|
||||
className="mr-3"
|
||||
loading={isSurveySaving}
|
||||
onClick={() => handleSaveAndGoBack()}>
|
||||
@@ -326,7 +325,6 @@ export const SurveyMenuBar = ({
|
||||
)}
|
||||
{localSurvey.status === "draft" && audiencePrompt && !isLinkSurvey && (
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
onClick={() => {
|
||||
setAudiencePrompt(false);
|
||||
setActiveId("settings");
|
||||
@@ -339,7 +337,6 @@ export const SurveyMenuBar = ({
|
||||
{localSurvey.status === "draft" && (!audiencePrompt || isLinkSurvey) && (
|
||||
<Button
|
||||
disabled={isSurveySaving || containsEmptyTriggers}
|
||||
variant="darkCTA"
|
||||
loading={isSurveyPublishing}
|
||||
onClick={handleSurveyPublish}>
|
||||
Publish
|
||||
|
||||
@@ -71,7 +71,7 @@ export const UpdateQuestionId = ({
|
||||
disabled={localSurvey.status !== "draft" && !question.isDraft}
|
||||
className={`h-10 ${isInputInvalid ? "border-red-300 focus:border-red-300" : ""}`}
|
||||
/>
|
||||
<Button variant="darkCTA" size="sm" onClick={saveAction} disabled={isButtonDisabled()}>
|
||||
<Button size="sm" onClick={saveAction} disabled={isButtonDisabled()}>
|
||||
Save
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -24,10 +24,7 @@ export const ConfirmationPage = ({ environmentId }: ConfirmationPageProps) => {
|
||||
Thanks a lot for upgrading your Formbricks subscription.
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
className="w-full justify-center"
|
||||
href={`/environments/${environmentId}/settings/billing`}>
|
||||
<Button className="w-full justify-center" href={`/environments/${environmentId}/settings/billing`}>
|
||||
Back to billing overview
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -100,7 +100,7 @@ export const AttributeSettingsTab = async ({ attributeClass, setOpen }: Attribut
|
||||
</div>
|
||||
{attributeClass.type !== "automatic" && (
|
||||
<div className="flex space-x-2">
|
||||
<Button type="submit" variant="darkCTA" loading={isAttributeBeingSubmitted}>
|
||||
<Button type="submit" loading={isAttributeBeingSubmitted}>
|
||||
Save changes
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -117,7 +117,7 @@ export const BasicCreateSegmentModal = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button variant="darkCTA" size="sm" onClick={() => setOpen(true)} EndIcon={PlusIcon}>
|
||||
<Button size="sm" onClick={() => setOpen(true)} EndIcon={PlusIcon}>
|
||||
Create segment
|
||||
</Button>
|
||||
|
||||
@@ -239,7 +239,6 @@ export const BasicCreateSegmentModal = ({
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
type="submit"
|
||||
loading={isCreatingSegment}
|
||||
disabled={isSaveDisabled}
|
||||
|
||||
@@ -236,7 +236,6 @@ export const BasicSegmentSettings = ({
|
||||
Delete
|
||||
</Button>
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
type="submit"
|
||||
loading={isUpdatingSegment}
|
||||
onClick={() => {
|
||||
|
||||
@@ -224,7 +224,7 @@ export const ActionSettingsTab = ({
|
||||
|
||||
{actionClass.type !== "automatic" && (
|
||||
<div className="flex space-x-2">
|
||||
<Button type="submit" variant="darkCTA" loading={isUpdatingAction}>
|
||||
<Button type="submit" loading={isUpdatingAction}>
|
||||
Save changes
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -27,12 +27,7 @@ export const AddActionModal = ({ environmentId, actionClasses }: AddActionModalP
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
size="sm"
|
||||
loading={isLoading}
|
||||
onClick={() => setOpen(true)}
|
||||
EndIcon={PlusIcon}>
|
||||
<Button size="sm" loading={isLoading} onClick={() => setOpen(true)} EndIcon={PlusIcon}>
|
||||
Add Action
|
||||
</Button>
|
||||
<Modal open={open} setOpen={setOpen} noPadding closeOnOutsideClick={false} restrictOverflow>
|
||||
|
||||
@@ -170,7 +170,7 @@ export const MainNavigation = ({
|
||||
isHidden: isViewer,
|
||||
},
|
||||
],
|
||||
[environment.id, pathname, isViewer]
|
||||
[environment.id, pathname, product?.config.channel, isViewer]
|
||||
);
|
||||
|
||||
const dropdownNavigation = [
|
||||
@@ -234,6 +234,7 @@ export const MainNavigation = ({
|
||||
</Link>
|
||||
)}
|
||||
<Button
|
||||
variant="minimal"
|
||||
size="icon"
|
||||
tooltipSide="right"
|
||||
onClick={toggleSidebar}
|
||||
|
||||
@@ -79,8 +79,8 @@ export const UrlShortenerForm = ({ webAppUrl }: { webAppUrl: string }) => {
|
||||
onBlur={handleUrlValidation}
|
||||
/>
|
||||
<Button
|
||||
variant="secondary"
|
||||
disabled={watch("url") === ""}
|
||||
variant="darkCTA"
|
||||
size="sm"
|
||||
type="submit"
|
||||
loading={isSubmitting}>
|
||||
|
||||
@@ -354,9 +354,7 @@ export const AddIntegrationModal = ({
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<Button variant="darkCTA" type="submit">
|
||||
Save
|
||||
</Button>
|
||||
<Button type="submit">Save</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -83,8 +83,7 @@ export const ManageIntegration = (props: ManageIntegrationProps) => {
|
||||
onClick={() => {
|
||||
setDefaultValues(null);
|
||||
handleModal(true);
|
||||
}}
|
||||
variant="darkCTA">
|
||||
}}>
|
||||
Link new table
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -288,7 +288,7 @@ export const AddIntegrationModal = ({
|
||||
Cancel
|
||||
</Button>
|
||||
)}
|
||||
<Button variant="darkCTA" type="submit" loading={isLinkingSheet}>
|
||||
<Button type="submit" loading={isLinkingSheet}>
|
||||
{selectedIntegration ? "Update" : "Link Sheet"}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -67,7 +67,6 @@ export const ManageIntegration = ({
|
||||
<span className="text-slate-500">Connected with {googleSheetIntegration.config.email}</span>
|
||||
</div>
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
onClick={() => {
|
||||
setSelectedIntegration(null);
|
||||
setOpenAddIntegrationModal(true);
|
||||
|
||||
@@ -6,9 +6,7 @@ const Loading = () => {
|
||||
<div className="mt-6 p-6">
|
||||
<GoBackButton />
|
||||
<div className="mb-6 text-right">
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
className="pointer-events-none animate-pulse cursor-not-allowed select-none bg-slate-200">
|
||||
<Button className="pointer-events-none animate-pulse cursor-not-allowed select-none bg-slate-200">
|
||||
Link new sheet
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -518,7 +518,6 @@ export const AddIntegrationModal = ({
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
type="submit"
|
||||
loading={isLinkingDatabase}
|
||||
disabled={mapping.filter((m) => m.error).length > 0}>
|
||||
|
||||
@@ -63,7 +63,6 @@ export const ManageIntegration = ({
|
||||
</span>
|
||||
</div>
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
onClick={() => {
|
||||
setSelectedIntegration(null);
|
||||
setOpenAddIntegrationModal(true);
|
||||
|
||||
@@ -6,9 +6,7 @@ const Loading = () => {
|
||||
<div className="mt-6 p-6">
|
||||
<GoBackButton />
|
||||
<div className="mb-6 text-right">
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
className="pointer-events-none animate-pulse cursor-not-allowed select-none bg-slate-200">
|
||||
<Button className="pointer-events-none animate-pulse cursor-not-allowed select-none bg-slate-200">
|
||||
Link new database
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -284,7 +284,7 @@ export const AddChannelMappingModal = ({
|
||||
Cancel
|
||||
</Button>
|
||||
)}
|
||||
<Button variant="darkCTA" type="submit" loading={isLinkingChannel}>
|
||||
<Button type="submit" loading={isLinkingChannel}>
|
||||
{selectedIntegration ? "Update" : "Link Channel"}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -65,7 +65,6 @@ export const ManageIntegration = ({
|
||||
<span className="text-slate-500">Connected with {slackIntegration.config.key.team.name}</span>
|
||||
</div>
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
onClick={() => {
|
||||
refreshChannels();
|
||||
setSelectedIntegration(null);
|
||||
|
||||
@@ -17,7 +17,6 @@ export const AddWebhookButton = ({ environment, surveys }: AddWebhookButtonProps
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
setAddWebhookModalOpen(true);
|
||||
|
||||
@@ -228,7 +228,7 @@ export const AddWebhookModal = ({ environmentId, surveys, open, setOpen }: AddWe
|
||||
}}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button variant="darkCTA" type="submit" loading={creatingWebhook}>
|
||||
<Button type="submit" loading={creatingWebhook}>
|
||||
Add Webhook
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -218,7 +218,7 @@ export const WebhookSettingsTab = ({ environmentId, webhook, surveys, setOpen }:
|
||||
</div>
|
||||
|
||||
<div className="flex space-x-2">
|
||||
<Button type="submit" variant="darkCTA" loading={isUpdatingWebhook}>
|
||||
<Button type="submit" loading={isUpdatingWebhook}>
|
||||
Save changes
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -63,9 +63,7 @@ export const AddApiKeyModal = ({ open, setOpen, onSubmit }: MemberModalProps) =>
|
||||
}}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button variant="darkCTA" type="submit">
|
||||
Add API Key
|
||||
</Button>
|
||||
<Button type="submit">Add API Key</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -117,7 +117,6 @@ export const EditAPIKeys = ({
|
||||
|
||||
<div>
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
size="sm"
|
||||
disabled={environmentId !== environmentTypeId}
|
||||
onClick={() => {
|
||||
|
||||
@@ -90,12 +90,7 @@ export const EditProductNameForm: React.FC<EditProductNameProps> = ({
|
||||
)}
|
||||
/>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
variant="darkCTA"
|
||||
size="sm"
|
||||
loading={isSubmitting}
|
||||
disabled={isSubmitting || !isDirty}>
|
||||
<Button type="submit" size="sm" loading={isSubmitting} disabled={isSubmitting || !isDirty}>
|
||||
Update
|
||||
</Button>
|
||||
</form>
|
||||
|
||||
@@ -78,7 +78,6 @@ export const EditWaitingTimeForm: React.FC<EditWaitingTimeProps> = ({ product })
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
variant="darkCTA"
|
||||
size="sm"
|
||||
className="w-fit"
|
||||
loading={isSubmitting}
|
||||
|
||||
@@ -169,7 +169,7 @@ export const EditLogo = ({ product, environmentId, isViewer }: EditLogoProps) =>
|
||||
</>
|
||||
)}
|
||||
{logoUrl && (
|
||||
<Button onClick={saveChanges} disabled={isLoading || isViewer} variant="darkCTA" size="sm">
|
||||
<Button onClick={saveChanges} disabled={isLoading || isViewer} size="sm">
|
||||
{isEditing ? "Save" : "Edit"}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@@ -182,7 +182,7 @@ export const EditPlacementForm = ({ product }: EditPlacementProps) => {
|
||||
</>
|
||||
)}
|
||||
|
||||
<Button variant="darkCTA" className="mt-4 w-fit" size="sm" loading={isSubmitting}>
|
||||
<Button className="mt-4 w-fit" size="sm" loading={isSubmitting}>
|
||||
Save
|
||||
</Button>
|
||||
</form>
|
||||
|
||||
@@ -200,7 +200,7 @@ export const ThemeStyling = ({ product, environmentId, colors, isUnsplashConfigu
|
||||
</div>
|
||||
|
||||
<div className="mt-4 flex items-center gap-2">
|
||||
<Button variant="darkCTA" size="sm" type="submit">
|
||||
<Button size="sm" type="submit">
|
||||
Save
|
||||
</Button>
|
||||
<Button
|
||||
|
||||
@@ -199,9 +199,7 @@ const Loading = () => {
|
||||
<div className={cn("absolute bottom-3 h-16 w-16 rounded bg-slate-700 sm:right-3")}></div>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
className="pointer-events-none mt-4 animate-pulse cursor-not-allowed select-none bg-slate-200">
|
||||
<Button className="pointer-events-none mt-4 animate-pulse cursor-not-allowed select-none bg-slate-200">
|
||||
Loading
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@ export const EditAvatar = ({ session }) => {
|
||||
<div>
|
||||
<ProfileAvatar userId={session.user.id} imageUrl={session.user.imageUrl} />
|
||||
|
||||
<Button className="mt-4" variant="darkCTA" size="sm" disabled={true}>
|
||||
<Button className="mt-4" size="sm" disabled={true}>
|
||||
Upload Image
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -145,9 +145,7 @@ export const DisableTwoFactorModal = ({ open, setOpen }: TDisableTwoFactorModalP
|
||||
Cancel
|
||||
</Button>
|
||||
|
||||
<Button variant="darkCTA" size="sm">
|
||||
Disable
|
||||
</Button>
|
||||
<Button size="sm">Disable</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -67,7 +67,6 @@ export const EditProfileDetailsForm = ({ user }: { user: TUser }) => {
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
variant="darkCTA"
|
||||
className="mt-4"
|
||||
size="sm"
|
||||
loading={isSubmitting}
|
||||
|
||||
@@ -100,9 +100,7 @@ const ConfirmPasswordForm = ({
|
||||
Cancel
|
||||
</Button>
|
||||
|
||||
<Button variant="darkCTA" size="sm">
|
||||
Confirm
|
||||
</Button>
|
||||
<Button size="sm">Confirm</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -134,7 +132,7 @@ const ScanQRCode = ({ dataUri, secret, setCurrentStep, setOpen }: TScanQRCodePro
|
||||
Cancel
|
||||
</Button>
|
||||
|
||||
<Button variant="darkCTA" size="sm" onClick={() => setCurrentStep("enterCode")}>
|
||||
<Button size="sm" onClick={() => setCurrentStep("enterCode")}>
|
||||
Next
|
||||
</Button>
|
||||
</div>
|
||||
@@ -207,9 +205,7 @@ const EnterCode = ({ setCurrentStep, setOpen, refreshData }: TEnableCodeProps) =
|
||||
Cancel
|
||||
</Button>
|
||||
|
||||
<Button variant="darkCTA" size="sm">
|
||||
Confirm
|
||||
</Button>
|
||||
<Button size="sm">Confirm</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -259,7 +255,6 @@ const DisplayBackupCodes = ({ backupCodes, setOpen }: TDisplayBackupCodesProps)
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(backupCodes.map((code) => formatBackupCode(code)).join("\n"));
|
||||
@@ -269,7 +264,6 @@ const DisplayBackupCodes = ({ backupCodes, setOpen }: TDisplayBackupCodesProps)
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
handleDownloadBackupCode();
|
||||
|
||||
@@ -170,10 +170,7 @@ const Page = async ({ params }) => {
|
||||
No call needed, no strings attached: Request a free 30-day trial license to test all features
|
||||
by filling out this form:
|
||||
</p>
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
href="https://app.formbricks.com/s/clvupq3y205i5yrm3sm9v1xt5"
|
||||
target="_blank">
|
||||
<Button href="https://app.formbricks.com/s/clvupq3y205i5yrm3sm9v1xt5" target="_blank">
|
||||
Request 30-day Trial License
|
||||
</Button>
|
||||
<p className="mt-2 text-xs text-slate-500">No credit card. No sales call. Just test it :)</p>
|
||||
|
||||
@@ -106,7 +106,7 @@ export const BulkInviteTab = ({ setOpen, onSubmit, canDoRoleManagement }: BulkIn
|
||||
Download CSV template
|
||||
</Button>
|
||||
</Link>
|
||||
<Button onClick={onImport} size="sm" variant="darkCTA" disabled={!csvFile}>
|
||||
<Button onClick={onImport} size="sm" disabled={!csvFile}>
|
||||
Import
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -96,7 +96,6 @@ export const OrganizationActions = ({
|
||||
{!isInviteDisabled && isAdminOrOwner && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="darkCTA"
|
||||
onClick={() => {
|
||||
setAddMemberModalOpen(true);
|
||||
}}>
|
||||
|
||||
@@ -92,7 +92,6 @@ export const EditOrganizationName = ({ organization, membershipRole }: EditOrgan
|
||||
<Button
|
||||
type="submit"
|
||||
className="mt-4"
|
||||
variant="darkCTA"
|
||||
size="sm"
|
||||
loading={isUpdatingOrganization}
|
||||
disabled={isOrganizationNameInputEmpty || currentOrganizationName === previousOrganizationName}>
|
||||
|
||||
@@ -86,7 +86,6 @@ export const EditOrganizationNameForm = ({ organization, membershipRole }: EditO
|
||||
<Button
|
||||
type="submit"
|
||||
className="mt-4"
|
||||
variant="darkCTA"
|
||||
size="sm"
|
||||
loading={isSubmitting}
|
||||
disabled={isSubmitting || !isDirty}>
|
||||
|
||||
@@ -93,7 +93,7 @@ export const IndividualInviteTab = ({
|
||||
}}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button variant="darkCTA" type="submit" size="sm" loading={isSubmitting}>
|
||||
<Button type="submit" size="sm" loading={isSubmitting}>
|
||||
Send Invitation
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -23,7 +23,7 @@ export const EmptyAppSurveys = ({ environment, surveyType = "app" }: TEmptyAppSu
|
||||
</p>
|
||||
|
||||
<Link className="mt-2" href={`/environments/${environment.id}/product/${surveyType}-connection`}>
|
||||
<Button variant="darkCTA" size="sm" className="flex w-[120px] justify-center">
|
||||
<Button size="sm" className="flex w-[120px] justify-center">
|
||||
Connect
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
@@ -65,7 +65,7 @@ export const ShareSurveyResults = ({
|
||||
Unpublish
|
||||
</Button>
|
||||
|
||||
<Button variant="darkCTA" className="text-center" href={surveyUrl} target="_blank">
|
||||
<Button className="text-center" href={surveyUrl} target="_blank">
|
||||
View site
|
||||
</Button>
|
||||
</div>
|
||||
@@ -84,11 +84,7 @@ export const ShareSurveyResults = ({
|
||||
have the link.
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="darkCTA"
|
||||
className="h-full text-center"
|
||||
onClick={() => handlePublish()}>
|
||||
<Button type="submit" className="h-full text-center" onClick={() => handlePublish()}>
|
||||
Publish to public web
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -48,7 +48,6 @@ export const SurveyAnalysisCTA = ({
|
||||
)}
|
||||
{!isViewer && (
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
size="sm"
|
||||
className="h-full w-full px-3"
|
||||
href={`/environments/${environment.id}/surveys/${survey.id}/edit`}>
|
||||
|
||||
@@ -78,7 +78,6 @@ export const EmailTab = ({ surveyId, email }: EmailTabProps) => {
|
||||
</>
|
||||
)}
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
title="view embed code for email"
|
||||
aria-label="view embed code for email"
|
||||
onClick={() => {
|
||||
|
||||
@@ -83,7 +83,6 @@ export const PanelInfoView = ({ handleInitialPageButton }: PanelInfoViewProps) =
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
className="justify-center"
|
||||
href="https://formbricks.com/docs/link-surveys/market-research-panel"
|
||||
target="_blank">
|
||||
|
||||
@@ -21,7 +21,6 @@ export const WebpageTab = ({ surveyUrl }) => {
|
||||
<div className="flex justify-between">
|
||||
<div></div>
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
title="Embed survey in your website"
|
||||
aria-label="Embed survey in your website"
|
||||
onClick={() => {
|
||||
|
||||
@@ -300,7 +300,7 @@ export const CustomFilter = ({ survey }: CustomFilterProps) => {
|
||||
{isDatePickerOpen && (
|
||||
<div ref={datePickerRef} className="absolute top-full z-50 my-2 rounded-md border bg-white">
|
||||
<Calendar
|
||||
initialFocus
|
||||
autoFocus
|
||||
mode="range"
|
||||
defaultMonth={dateRange?.from}
|
||||
selected={hoveredRange ? hoveredRange : dateRange}
|
||||
|
||||
@@ -279,7 +279,7 @@ export const ResponseFilter = ({ survey }: ResponseFilterProps) => {
|
||||
<Plus width={18} height={18} className="ml-2" />
|
||||
</Button>
|
||||
<div className="flex gap-2">
|
||||
<Button size="sm" variant="darkCTA" onClick={handleApplyFilters}>
|
||||
<Button size="sm" onClick={handleApplyFilters}>
|
||||
Apply filters
|
||||
</Button>
|
||||
<Button size="sm" variant="minimal" onClick={handleClearAllFilters}>
|
||||
|
||||
@@ -64,11 +64,7 @@ const Page = async ({ params, searchParams }: SurveyTemplateProps) => {
|
||||
const currentProductChannel = product.config.channel ?? null;
|
||||
|
||||
const CreateSurveyButton = (
|
||||
<Button
|
||||
size="sm"
|
||||
href={`/environments/${environment.id}/surveys/templates`}
|
||||
variant="darkCTA"
|
||||
EndIcon={PlusIcon}>
|
||||
<Button size="sm" href={`/environments/${environment.id}/surveys/templates`} EndIcon={PlusIcon}>
|
||||
New survey
|
||||
</Button>
|
||||
);
|
||||
|
||||
@@ -59,7 +59,7 @@ export const PasswordResetForm = ({}) => {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Button type="submit" variant="darkCTA" className="w-full justify-center" loading={loading}>
|
||||
<Button type="submit" className="w-full justify-center" loading={loading}>
|
||||
Reset password
|
||||
</Button>
|
||||
<div className="mt-3 text-center">
|
||||
|
||||
@@ -92,12 +92,7 @@ export const ResetPasswordForm = () => {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="darkCTA"
|
||||
disabled={!isValid}
|
||||
className="w-full justify-center"
|
||||
loading={loading}>
|
||||
<Button type="submit" disabled={!isValid} className="w-full justify-center" loading={loading}>
|
||||
Reset password
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -210,7 +210,6 @@ export const SigninForm = ({
|
||||
formRef.current.requestSubmit();
|
||||
}
|
||||
}}
|
||||
variant="darkCTA"
|
||||
className="w-full justify-center"
|
||||
loading={loggingIn}>
|
||||
{totpLogin ? "Submit" : "Login with Email"}
|
||||
|
||||
@@ -43,9 +43,7 @@ const Page = async ({ searchParams }) => {
|
||||
<Button variant="secondary" href="/support">
|
||||
Contact support
|
||||
</Button>
|
||||
<Button variant="darkCTA" href="/">
|
||||
Go to app
|
||||
</Button>
|
||||
<Button href="/">Go to app</Button>
|
||||
</ContentLayout>
|
||||
);
|
||||
} else if (!session) {
|
||||
@@ -58,9 +56,7 @@ const Page = async ({ searchParams }) => {
|
||||
href={`/auth/signup?inviteToken=${searchParams.token}&email=${encodedEmail}`}>
|
||||
Create account
|
||||
</Button>
|
||||
<Button variant="darkCTA" href={`/auth/login?callbackUrl=${redirectUrl}&email=${encodedEmail}`}>
|
||||
Login
|
||||
</Button>
|
||||
<Button href={`/auth/login?callbackUrl=${redirectUrl}&email=${encodedEmail}`}>Login</Button>
|
||||
</ContentLayout>
|
||||
);
|
||||
} else if (session.user?.email !== email) {
|
||||
@@ -71,9 +67,7 @@ const Page = async ({ searchParams }) => {
|
||||
<Button variant="secondary" href="/support">
|
||||
Contact support
|
||||
</Button>
|
||||
<Button variant="darkCTA" href="/">
|
||||
Go to app
|
||||
</Button>
|
||||
<Button href="/">Go to app</Button>
|
||||
</ContentLayout>
|
||||
);
|
||||
} else {
|
||||
@@ -100,9 +94,7 @@ const Page = async ({ searchParams }) => {
|
||||
});
|
||||
return (
|
||||
<ContentLayout headline="You’re in 🎉" description="Welcome to the organization.">
|
||||
<Button variant="darkCTA" href="/">
|
||||
Go to app
|
||||
</Button>
|
||||
<Button href="/">Go to app</Button>
|
||||
</ContentLayout>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,9 +16,7 @@ const Error = ({ error, reset }: { error: Error; reset: () => void }) => {
|
||||
<Button variant="secondary" onClick={() => reset()} className="mr-2">
|
||||
Try again
|
||||
</Button>
|
||||
<Button variant="darkCTA" onClick={() => (window.location.href = "/")}>
|
||||
Go to Dashboard
|
||||
</Button>
|
||||
<Button onClick={() => (window.location.href = "/")}>Go to Dashboard</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -38,7 +38,7 @@ export const SurveyInactive = ({
|
||||
: descriptions[status]}
|
||||
</p>
|
||||
{!(status === "completed" && surveyClosedMessage) && status !== "link invalid" && (
|
||||
<Button variant="darkCTA" className="mt-2" href="https://formbricks.com">
|
||||
<Button className="mt-2" href="https://formbricks.com">
|
||||
Create your own
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@@ -115,7 +115,7 @@ export const VerifyEmail = ({
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
onKeyPress={handleKeyPress}
|
||||
/>
|
||||
<Button variant="darkCTA" onClick={() => submitEmail(email)} loading={isLoading}>
|
||||
<Button onClick={() => submitEmail(email)} loading={isLoading}>
|
||||
Verify
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@ const NotFound = () => {
|
||||
<HelpCircleIcon className="h-20 w-20" />,
|
||||
<h1 className="text-4xl font-bold text-slate-800">Survey not found.</h1>
|
||||
<p className="text-lg leading-10 text-slate-500">There is no survey with this ID.</p>
|
||||
<Button variant="darkCTA" className="mt-2" href="https://formbricks.com">
|
||||
<Button className="mt-2" href="https://formbricks.com">
|
||||
Create your own
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -24,7 +24,7 @@ const Page = () => {
|
||||
<b>full control over your data.</b> Always.
|
||||
</p>
|
||||
</div>
|
||||
<Button variant="darkCTA" href="/setup/signup" className="mt-6">
|
||||
<Button href="/setup/signup" className="mt-6">
|
||||
Get started
|
||||
</Button>
|
||||
|
||||
|
||||
@@ -108,7 +108,6 @@ export const InviteMembers = ({ IS_SMTP_CONFIGURED, organizationId }: InviteMemb
|
||||
|
||||
<div className="space-y-2">
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
className="flex w-80 justify-center"
|
||||
type="submit"
|
||||
loading={isSubmitting}
|
||||
|
||||
@@ -68,7 +68,6 @@ export const CreateOrganization = () => {
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="darkCTA"
|
||||
className="flex w-80 justify-center"
|
||||
loading={isSubmitting}
|
||||
disabled={isSubmitting || organizationName.trim() === ""}>
|
||||
|
||||
@@ -34,9 +34,7 @@ export const RemovedFromOrganization = ({ session, isFormbricksCloud }: RemovedF
|
||||
isFormbricksCloud={isFormbricksCloud}
|
||||
formbricksLogout={formbricksLogout}
|
||||
/>
|
||||
<Button variant="darkCTA" onClick={() => setIsModalOpen(true)}>
|
||||
Delete account
|
||||
</Button>
|
||||
<Button onClick={() => setIsModalOpen(true)}>Delete account</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -20,7 +20,6 @@ import { RATE_LIMITING_DISABLED, WEBAPP_URL } from "@formbricks/lib/constants";
|
||||
|
||||
export const middleware = async (request: NextRequest) => {
|
||||
// issue with next auth types & Next 15; let's review when new fixes are available
|
||||
// @ts-expect-error
|
||||
const token = await getToken({ req: request });
|
||||
|
||||
if (isAuthProtectedRoute(request.nextUrl.pathname) && !token) {
|
||||
|
||||
@@ -19,9 +19,12 @@ const getHostname = (url) => {
|
||||
const nextConfig = {
|
||||
assetPrefix: process.env.ASSET_PREFIX_URL || undefined,
|
||||
output: "standalone",
|
||||
serverExternalPackages: ["@aws-sdk"],
|
||||
poweredByHeader: false,
|
||||
experimental: {
|
||||
serverComponentsExternalPackages: ["@aws-sdk"],
|
||||
staleTimes: {
|
||||
dynamic: 0,
|
||||
},
|
||||
outputFileTracingIncludes: {
|
||||
"app/api/packages": ["../../packages/js-core/dist/*", "../../packages/surveys/dist/*"],
|
||||
},
|
||||
|
||||
@@ -26,50 +26,50 @@
|
||||
"@formbricks/surveys": "workspace:*",
|
||||
"@formbricks/types": "workspace:*",
|
||||
"@formbricks/ui": "workspace:*",
|
||||
"@hookform/resolvers": "^3.6.0",
|
||||
"@hookform/resolvers": "^3.9.0",
|
||||
"@json2csv/node": "^7.0.6",
|
||||
"@paralleldrive/cuid2": "^2.2.2",
|
||||
"@radix-ui/react-collapsible": "^1.1.0",
|
||||
"@react-email/components": "^0.0.19",
|
||||
"@sentry/nextjs": "^8.12.0",
|
||||
"@react-email/components": "^0.0.22",
|
||||
"@sentry/nextjs": "^8.22.0",
|
||||
"@vercel/og": "^0.6.2",
|
||||
"@vercel/speed-insights": "^1.0.12",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"dotenv": "^16.4.5",
|
||||
"encoding": "^0.1.13",
|
||||
"framer-motion": "11.2.12",
|
||||
"framer-motion": "11.3.20",
|
||||
"googleapis": "^140.0.1",
|
||||
"jiti": "^1.21.6",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"lodash": "^4.17.21",
|
||||
"lru-cache": "^10.2.2",
|
||||
"lucide-react": "^0.397.0",
|
||||
"mime": "^4.0.3",
|
||||
"next": "15.0.0-rc.0",
|
||||
"next-safe-action": "^7.1.3",
|
||||
"lru-cache": "^11.0.0",
|
||||
"lucide-react": "^0.418.0",
|
||||
"mime": "^4.0.4",
|
||||
"next": "14.2.5",
|
||||
"next-safe-action": "^7.4.3",
|
||||
"optional": "^0.1.4",
|
||||
"otplib": "^12.0.1",
|
||||
"papaparse": "^5.4.1",
|
||||
"posthog-js": "^1.141.4",
|
||||
"posthog-js": "^1.154.0",
|
||||
"prismjs": "^1.29.0",
|
||||
"qrcode": "^1.5.3",
|
||||
"react": "19.0.0-rc-935180c7e0-20240524",
|
||||
"react-dom": "19.0.0-rc-935180c7e0-20240524",
|
||||
"react-hook-form": "^7.52.0",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
"react-hook-form": "^7.52.1",
|
||||
"react-hot-toast": "^2.4.1",
|
||||
"redis": "^4.6.14",
|
||||
"redis": "^4.7.0",
|
||||
"sharp": "^0.33.4",
|
||||
"ua-parser-js": "^1.0.38",
|
||||
"webpack": "^5.92.1",
|
||||
"webpack": "^5.93.0",
|
||||
"xlsx": "^0.18.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@formbricks/config-typescript": "workspace:*",
|
||||
"@formbricks/eslint-config": "workspace:*",
|
||||
"@neshca/cache-handler": "^1.3.2",
|
||||
"@neshca/cache-handler": "^1.5.1",
|
||||
"@types/bcryptjs": "^2.4.6",
|
||||
"@types/lodash": "^4.17.5",
|
||||
"@types/markdown-it": "^14.1.1",
|
||||
"@types/lodash": "^4.17.7",
|
||||
"@types/markdown-it": "^14.1.2",
|
||||
"@types/papaparse": "^5.3.14",
|
||||
"@types/qrcode": "^1.5.5"
|
||||
}
|
||||
|
||||
14
package.json
14
package.json
@@ -32,14 +32,14 @@
|
||||
"storybook": "turbo run storybook"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.45.0",
|
||||
"@playwright/test": "^1.45.3",
|
||||
"@formbricks/eslint-config": "workspace:*",
|
||||
"eslint": "^8.57.0",
|
||||
"husky": "^9.0.11",
|
||||
"husky": "^9.1.4",
|
||||
"lint-staged": "^15.2.7",
|
||||
"rimraf": "^5.0.7",
|
||||
"tsx": "^4.15.7",
|
||||
"turbo": "^2.0.5"
|
||||
"rimraf": "^6.0.1",
|
||||
"tsx": "^4.16.5",
|
||||
"turbo": "^2.0.11"
|
||||
},
|
||||
"lint-staged": {
|
||||
"(apps|packages)/**/*.{js,ts,jsx,tsx}": [
|
||||
@@ -64,7 +64,7 @@
|
||||
"showDetails": true
|
||||
},
|
||||
"dependencies": {
|
||||
"@changesets/cli": "^2.27.6",
|
||||
"playwright": "^1.45.0"
|
||||
"@changesets/cli": "^2.27.7",
|
||||
"playwright": "^1.45.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
"@formbricks/config-typescript": "workspace:*",
|
||||
"@formbricks/types": "workspace:*",
|
||||
"@formbricks/eslint-config": "workspace:*",
|
||||
"terser": "^5.31.1",
|
||||
"vite": "^5.3.1",
|
||||
"terser": "^5.31.3",
|
||||
"vite": "^5.3.5",
|
||||
"vite-plugin-dts": "^3.9.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@next/eslint-plugin-next": "^14.2.4",
|
||||
"@typescript-eslint/eslint-plugin": "^7.16.0",
|
||||
"@typescript-eslint/parser": "^7.16.0",
|
||||
"@next/eslint-plugin-next": "^14.2.5",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"@vercel/style-guide": "^6.0.0",
|
||||
"eslint-config-next": "^14.2.4",
|
||||
"eslint-config-next": "^14.2.5",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-config-turbo": "^2.0.4",
|
||||
"eslint-plugin-react": "7.34.3",
|
||||
"eslint-config-turbo": "^2.0.11",
|
||||
"eslint-plugin-react": "7.35.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
"eslint-plugin-react-refresh": "^0.4.7"
|
||||
"eslint-plugin-react-refresh": "^0.4.9"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||
"prettier": "^3.3.2",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-plugin-tailwindcss": "^0.6.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"@tailwindcss/typography": "^0.5.13",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"postcss": "^8.4.38",
|
||||
"tailwindcss": "^3.4.4"
|
||||
"postcss": "^8.4.40",
|
||||
"tailwindcss": "^3.4.7"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"clean": "rimraf node_modules dist turbo"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "20.14.5",
|
||||
"@types/node": "22.0.2",
|
||||
"@types/react": "18.3.3",
|
||||
"@types/react-dom": "18.3.0",
|
||||
"typescript": "5.4.5"
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
"data-migration:segments-cleanup": "ts-node ./data-migrations/20240712123456_segments_cleanup/data-migration.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "^5.16.2",
|
||||
"@prisma/client": "^5.17.0",
|
||||
"@prisma/extension-accelerate": "^1.1.0",
|
||||
"dotenv-cli": "^7.4.2"
|
||||
},
|
||||
@@ -53,7 +53,7 @@
|
||||
"@formbricks/types": "workspace:*",
|
||||
"@paralleldrive/cuid2": "^2.2.2",
|
||||
"@formbricks/eslint-config": "workspace:*",
|
||||
"prisma": "^5.16.2",
|
||||
"prisma": "^5.17.0",
|
||||
"prisma-dbml-generator": "^0.12.0",
|
||||
"prisma-json-types-generator": "^3.0.4",
|
||||
"ts-node": "^10.9.2",
|
||||
|
||||
@@ -125,8 +125,7 @@ export function CreateSegmentModal({
|
||||
onClick={() => {
|
||||
setOpen(true);
|
||||
}}
|
||||
size="sm"
|
||||
variant="darkCTA">
|
||||
size="sm">
|
||||
Create segment
|
||||
</Button>
|
||||
|
||||
@@ -245,8 +244,7 @@ export function CreateSegmentModal({
|
||||
onClick={() => {
|
||||
handleCreateSegment();
|
||||
}}
|
||||
type="submit"
|
||||
variant="darkCTA">
|
||||
type="submit">
|
||||
Create segment
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -229,8 +229,7 @@ export function SegmentSettings({
|
||||
onClick={() => {
|
||||
handleUpdateSegment();
|
||||
}}
|
||||
type="submit"
|
||||
variant="darkCTA">
|
||||
type="submit">
|
||||
Save changes
|
||||
</Button>
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ export function DefaultLanguageSelect({
|
||||
onConfirm: () => {
|
||||
handleDefaultLanguageChange(languageCode);
|
||||
},
|
||||
buttonVariant: "darkCTA",
|
||||
buttonVariant: "primary",
|
||||
});
|
||||
}}
|
||||
value={`${defaultLanguage?.code}`}>
|
||||
|
||||
@@ -235,7 +235,7 @@ const EditSaveButtons: React.FC<{
|
||||
}> = ({ isEditing, onEdit, onSave, onCancel }) =>
|
||||
isEditing ? (
|
||||
<div className="flex gap-4">
|
||||
<Button onClick={onSave} size="sm" variant="darkCTA">
|
||||
<Button onClick={onSave} size="sm">
|
||||
Save changes
|
||||
</Button>
|
||||
<Button onClick={onCancel} size="sm" variant="minimal">
|
||||
@@ -243,7 +243,7 @@ const EditSaveButtons: React.FC<{
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<Button className="w-fit" onClick={onEdit} size="sm" variant="darkCTA">
|
||||
<Button className="w-fit" onClick={onEdit} size="sm">
|
||||
Edit languages
|
||||
</Button>
|
||||
);
|
||||
|
||||
@@ -34,7 +34,7 @@ export interface ConfirmationModalProps {
|
||||
open: boolean;
|
||||
title: string;
|
||||
buttonText: string;
|
||||
buttonVariant?: "darkCTA" | "warn";
|
||||
buttonVariant?: "primary" | "warn";
|
||||
onConfirm: () => void;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,16 +23,16 @@
|
||||
"@formbricks/database": "workspace:*",
|
||||
"@formbricks/lib": "workspace:*",
|
||||
"@paralleldrive/cuid2": "^2.2.2",
|
||||
"@radix-ui/react-collapsible": "^1.0.3",
|
||||
"https-proxy-agent": "^7.0.4",
|
||||
"lucide-react": "^0.395.0",
|
||||
"next": "^14.2.4",
|
||||
"@radix-ui/react-collapsible": "^1.1.0",
|
||||
"https-proxy-agent": "^7.0.5",
|
||||
"lucide-react": "^0.418.0",
|
||||
"next": "^14.2.5",
|
||||
"next-auth": "^4.24.7",
|
||||
"node-fetch": "^3.3.2",
|
||||
"react-hook-form": "^7.52.0",
|
||||
"react-hook-form": "^7.52.1",
|
||||
"react-hot-toast": "^2.4.1",
|
||||
"server-only": "^0.0.1",
|
||||
"stripe": "^15.12.0",
|
||||
"stripe": "^16.5.0",
|
||||
"zod": "^3.23.8"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
"@formbricks/lib": "workspace:*",
|
||||
"@formbricks/types": "workspace:*",
|
||||
"@formbricks/ui": "workspace:*",
|
||||
"@react-email/components": "^0.0.19",
|
||||
"@react-email/render": "^0.0.15",
|
||||
"lucide-react": "^0.395.0",
|
||||
"nodemailer": "^6.9.13",
|
||||
"react-email": "^2.1.4"
|
||||
"@react-email/components": "^0.0.22",
|
||||
"@react-email/render": "^0.0.17",
|
||||
"lucide-react": "^0.418.0",
|
||||
"nodemailer": "^6.9.14",
|
||||
"react-email": "^2.1.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/nodemailer": "^6.4.15",
|
||||
|
||||
@@ -59,8 +59,8 @@
|
||||
"@formbricks/config-typescript": "workspace:*",
|
||||
"@formbricks/types": "workspace:*",
|
||||
"@formbricks/eslint-config": "workspace:*",
|
||||
"terser": "^5.31.1",
|
||||
"vite": "^5.3.1",
|
||||
"terser": "^5.31.3",
|
||||
"vite": "^5.3.5",
|
||||
"vite-plugin-dts": "^3.9.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,8 +55,8 @@
|
||||
"@formbricks/config-typescript": "workspace:*",
|
||||
"@formbricks/eslint-config": "workspace:*",
|
||||
"@formbricks/types": "workspace:*",
|
||||
"terser": "^5.31.1",
|
||||
"vite": "^5.3.1",
|
||||
"terser": "^5.31.3",
|
||||
"vite": "^5.3.5",
|
||||
"vite-plugin-dts": "^3.9.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -27,11 +27,11 @@ export const getRoleBasedSchema = <T extends z.ZodRawShape>(
|
||||
return typeof data === "boolean" && data === true ? schema.strict() : data;
|
||||
};
|
||||
|
||||
export const formatErrors = (errors: ZodIssue[]) => {
|
||||
export const formatErrors = (issues: ZodIssue[]): Record<string, { _errors: string[] }> => {
|
||||
return {
|
||||
...errors.reduce((acc, error) => {
|
||||
acc[error.path.join(".")] = {
|
||||
_errors: [error.message],
|
||||
...issues.reduce((acc, issue) => {
|
||||
acc[issue.path.join(".")] = {
|
||||
_errors: [issue.message],
|
||||
};
|
||||
return acc;
|
||||
}, {}),
|
||||
@@ -56,6 +56,7 @@ export const checkAuthorization = async <T extends z.ZodRawShape>({
|
||||
const resultSchema = getRoleBasedSchema(schema, role, ...rules);
|
||||
const parsedResult = resultSchema.safeParse(data);
|
||||
if (!parsedResult.success) {
|
||||
// @ts-expect-error -- TODO: match dynamic next-safe-action types
|
||||
return returnValidationErrors(resultSchema, formatErrors(parsedResult.error.issues));
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -168,7 +168,7 @@ export const CUSTOMER_IO_SITE_ID = env.CUSTOMER_IO_SITE_ID;
|
||||
export const CUSTOMER_IO_API_KEY = env.CUSTOMER_IO_API_KEY;
|
||||
export const UNSPLASH_ACCESS_KEY = env.UNSPLASH_ACCESS_KEY;
|
||||
|
||||
export const STRIPE_API_VERSION = "2024-04-10";
|
||||
export const STRIPE_API_VERSION = "2024-06-20";
|
||||
|
||||
// Maximum number of attribute classes allowed:
|
||||
export const MAX_ATTRIBUTE_CLASSES_PER_ENVIRONMENT = 150 as const;
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
"test": "dotenv -e ../../.env -- vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "3.600.0",
|
||||
"@aws-sdk/s3-presigned-post": "3.600.0",
|
||||
"@aws-sdk/s3-request-presigner": "3.600.0",
|
||||
"@aws-sdk/client-s3": "3.621.0",
|
||||
"@aws-sdk/s3-presigned-post": "3.621.0",
|
||||
"@aws-sdk/s3-request-presigner": "3.621.0",
|
||||
"@formbricks/api": "*",
|
||||
"@formbricks/database": "*",
|
||||
"@formbricks/types": "*",
|
||||
"@paralleldrive/cuid2": "^2.2.2",
|
||||
"@t3-oss/env-nextjs": "^0.10.1",
|
||||
"@t3-oss/env-nextjs": "^0.11.0",
|
||||
"@ungap/structured-clone": "^1.2.0",
|
||||
"aws-crt": "^1.21.3",
|
||||
"date-fns": "^3.6.0",
|
||||
@@ -33,7 +33,7 @@
|
||||
"posthog-node": "^4.0.1",
|
||||
"server-only": "^0.0.1",
|
||||
"superjson": "^2.2.1",
|
||||
"tailwind-merge": "^2.3.0"
|
||||
"tailwind-merge": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@formbricks/config-typescript": "workspace:*",
|
||||
@@ -43,7 +43,7 @@
|
||||
"dotenv": "^16.4.5",
|
||||
"@formbricks/eslint-config": "workspace:*",
|
||||
"ts-node": "^10.9.2",
|
||||
"vitest": "^1.6.0",
|
||||
"vitest-mock-extended": "^1.3.1"
|
||||
"vitest": "^2.0.5",
|
||||
"vitest-mock-extended": "^2.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,17 +41,17 @@
|
||||
"@formbricks/eslint-config": "workspace:*",
|
||||
"@formbricks/lib": "workspace:*",
|
||||
"@formbricks/types": "workspace:*",
|
||||
"@preact/preset-vite": "^2.8.2",
|
||||
"@preact/preset-vite": "^2.9.0",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"concurrently": "8.2.2",
|
||||
"isomorphic-dompurify": "^2.12.0",
|
||||
"postcss": "^8.4.38",
|
||||
"preact": "^10.22.0",
|
||||
"isomorphic-dompurify": "^2.14.0",
|
||||
"postcss": "^8.4.40",
|
||||
"preact": "^10.23.1",
|
||||
"react-date-picker": "^11.0.0",
|
||||
"serve": "14.2.3",
|
||||
"tailwindcss": "^3.4.4",
|
||||
"terser": "^5.31.1",
|
||||
"vite": "^5.3.1",
|
||||
"tailwindcss": "^3.4.7",
|
||||
"terser": "^5.31.3",
|
||||
"vite": "^5.3.5",
|
||||
"vite-plugin-dts": "^3.9.1",
|
||||
"vite-tsconfig-paths": "^4.3.2"
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ export const AlertDialog = ({
|
||||
{declineBtnLabel || "Discard"}
|
||||
</Button>
|
||||
<Button
|
||||
variant="darkCTA"
|
||||
onClick={() => {
|
||||
if (onConfirm) {
|
||||
onConfirm();
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../Too
|
||||
type SVGComponent = React.FunctionComponent<React.SVGProps<SVGSVGElement>> | LucideIcon;
|
||||
|
||||
export type ButtonBaseProps = {
|
||||
variant?: "highlight" | "primary" | "secondary" | "minimal" | "warn" | "alert" | "darkCTA";
|
||||
variant?: "highlight" | "primary" | "secondary" | "minimal" | "warn" | "alert";
|
||||
size?: "base" | "sm" | "lg" | "fab" | "icon";
|
||||
loading?: boolean;
|
||||
disabled?: boolean;
|
||||
@@ -79,8 +79,8 @@ export const Button: React.ForwardRefExoticComponent<
|
||||
: "text-white bg-brand-dark focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-slate-900 transition ease-in-out delay-50 hover:scale-105"),
|
||||
variant === "primary" &&
|
||||
(disabled
|
||||
? "border border-transparent bg-slate-400 text-white"
|
||||
: "text-white bg-brand-dark hover:bg-brand focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-slate-900"),
|
||||
? "text-slate-400 dark:text-slate-500 bg-slate-200 dark:bg-slate-800"
|
||||
: "text-slate-100 hover:text-slate-50 bg-gradient-to-br from-slate-900 to-slate-800 hover:from-slate-800 hover:to-slate-700 dark:text-slate-300 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:bg-slate-700 focus:ring-neutral-500"),
|
||||
|
||||
variant === "minimal" &&
|
||||
(disabled
|
||||
@@ -98,10 +98,6 @@ export const Button: React.ForwardRefExoticComponent<
|
||||
(disabled
|
||||
? "text-slate-400 bg-transparent"
|
||||
: "hover:bg-red-200 text-red-700 bg-red-100 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:bg-red-50 focus:ring-red-500"),
|
||||
variant === "darkCTA" &&
|
||||
(disabled
|
||||
? "text-slate-400 dark:text-slate-500 bg-slate-200 dark:bg-slate-800"
|
||||
: "text-slate-100 hover:text-slate-50 bg-gradient-to-br from-slate-900 to-slate-800 hover:from-slate-800 hover:to-slate-700 dark:text-slate-300 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:bg-slate-700 focus:ring-neutral-500"),
|
||||
|
||||
// set not-allowed cursor if disabled
|
||||
loading ? "cursor-wait" : disabled ? "cursor-not-allowed" : "",
|
||||
|
||||
@@ -13,7 +13,7 @@ const meta = {
|
||||
argTypes: {
|
||||
variant: {
|
||||
control: "select",
|
||||
options: ["highlight", "primary", "secondary", "minimal", "warn", "alert", "darkCTA"],
|
||||
options: ["highlight", "primary", "secondary", "minimal", "warn", "alert"],
|
||||
},
|
||||
size: { control: "select", options: ["base", "sm", "lg", "fab", "icon"] },
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||
import * as React from "react";
|
||||
import { DayPicker } from "react-day-picker";
|
||||
import { Chevron, DayPicker } from "react-day-picker";
|
||||
import { cn } from "@formbricks/lib/cn";
|
||||
|
||||
// import { buttonVariants } from "@/components/ui/button";
|
||||
@@ -40,8 +40,14 @@ export const Calendar = ({ className, classNames, showOutsideDays = true, ...pro
|
||||
...classNames,
|
||||
}}
|
||||
components={{
|
||||
IconLeft: () => <ChevronLeft className="h-4 w-4" />,
|
||||
IconRight: () => <ChevronRight className="h-4 w-4" />,
|
||||
Chevron: (props) => {
|
||||
if (props.orientation === "left") {
|
||||
return <ChevronLeft className="h-4 w-4" />;
|
||||
} else if (props.orientation === "right") {
|
||||
return <ChevronRight className="h-4 w-4" />;
|
||||
}
|
||||
return <Chevron {...props} />;
|
||||
},
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
|
||||
@@ -51,7 +51,7 @@ export const Card: React.FC<CardProps> = ({
|
||||
<p className="text-xs text-slate-500">{description}</p>
|
||||
<div className="mt-4 flex space-x-2">
|
||||
{connectHref && (
|
||||
<Button href={connectHref} target={connectNewTab ? "_blank" : "_self"} size="sm" variant="darkCTA">
|
||||
<Button href={connectHref} target={connectNewTab ? "_blank" : "_self"} size="sm">
|
||||
{connectText}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user