Compare commits

...

7 Commits

Author SHA1 Message Date
Piyush Gupta
edd1b6bc0d fix: E2E tests 2024-10-15 12:02:55 +05:30
Johannes
2cd51e18f4 Merge branch 'main' into feat/3214-unify-menu 2024-10-14 18:31:51 -07:00
Johannes
b13472540e Merge branch 'main' of https://github.com/formbricks/formbricks into feat/3214-unify-menu 2024-10-14 17:52:29 -07:00
Johannes
101c856496 final tweaks 2024-10-14 17:50:40 -07:00
Dev Dalia
22744ee185 Merge branch 'formbricks:main' into feat/3214-unify-menu 2024-10-11 00:04:42 +05:30
devcodes9
8adf9be9d3 feat: generalisedropdown menu item and content 2024-10-10 23:58:46 +05:30
devcodes9
666f699858 feat: match main nav with ui 2024-10-10 10:21:47 +05:30
23 changed files with 119 additions and 149 deletions

View File

@@ -18,7 +18,7 @@ export const AddEndingCardButton = ({ localSurvey, addEndingCard }: AddEndingCar
<PlusIcon className="h-6 w-6 text-white" /> <PlusIcon className="h-6 w-6 text-white" />
</div> </div>
<div className="px-4 py-3 text-sm"> <div className="px-4 py-3 text-sm">
<p className="font-semibold">Add Ending</p> <p className="font-semibold">Add ending</p>
</div> </div>
</div> </div>
); );

View File

@@ -39,7 +39,7 @@ export const AddQuestionButton = ({ addQuestion, product, isCxMode }: AddQuestio
<PlusIcon className="h-5 w-5 text-white" /> <PlusIcon className="h-5 w-5 text-white" />
</div> </div>
<div className="px-4 py-3"> <div className="px-4 py-3">
<p className="text-sm font-semibold">Add Question</p> <p className="text-sm font-semibold">Add question</p>
<p className="mt-1 text-xs text-slate-500">Add a new question to your survey</p> <p className="mt-1 text-xs text-slate-500">Add a new question to your survey</p>
</div> </div>
</div> </div>

View File

@@ -141,37 +141,33 @@ export function ConditionalLogic({
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent> <DropdownMenuContent>
<DropdownMenuItem <DropdownMenuItem
className="flex items-center gap-2"
onClick={() => { onClick={() => {
duplicateLogic(logicItemIdx); duplicateLogic(logicItemIdx);
}}> }}
<CopyIcon className="h-4 w-4" /> icon={<CopyIcon className="h-4 w-4" />}>
Duplicate Duplicate
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
className="flex items-center gap-2"
disabled={logicItemIdx === 0} disabled={logicItemIdx === 0}
onClick={() => { onClick={() => {
moveLogic(logicItemIdx, logicItemIdx - 1); moveLogic(logicItemIdx, logicItemIdx - 1);
}}> }}
<ArrowUpIcon className="h-4 w-4" /> icon={<ArrowUpIcon className="h-4 w-4" />}>
Move up Move up
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
className="flex items-center gap-2"
disabled={logicItemIdx === (question.logic ?? []).length - 1} disabled={logicItemIdx === (question.logic ?? []).length - 1}
onClick={() => { onClick={() => {
moveLogic(logicItemIdx, logicItemIdx + 1); moveLogic(logicItemIdx, logicItemIdx + 1);
}}> }}
<ArrowDownIcon className="h-4 w-4" /> icon={<ArrowDownIcon className="h-4 w-4" />}>
Move down Move down
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
className="flex items-center gap-2"
onClick={() => { onClick={() => {
handleRemoveLogic(logicItemIdx); handleRemoveLogic(logicItemIdx);
}}> }}
<TrashIcon className="h-4 w-4" /> icon={<TrashIcon className="h-4 w-4" />}>
Remove Remove
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>

View File

@@ -75,11 +75,11 @@ export const EditWelcomeCard = ({
className="flex-1 rounded-r-lg border border-slate-200 transition-all duration-300 ease-in-out"> className="flex-1 rounded-r-lg border border-slate-200 transition-all duration-300 ease-in-out">
<Collapsible.CollapsibleTrigger <Collapsible.CollapsibleTrigger
asChild asChild
className="flex cursor-pointer justify-between p-4 hover:bg-slate-50"> className="flex cursor-pointer justify-between rounded-r-lg p-4 hover:bg-slate-50">
<div> <div>
<div className="inline-flex"> <div className="inline-flex">
<div> <div>
<p className="text-sm font-semibold">Welcome Card</p> <p className="text-sm font-semibold">Welcome card</p>
{!open && ( {!open && (
<p className="mt-1 truncate text-xs text-slate-500"> <p className="mt-1 truncate text-xs text-slate-500">
{localSurvey?.welcomeCard?.enabled ? "Shown" : "Hidden"} {localSurvey?.welcomeCard?.enabled ? "Shown" : "Hidden"}

View File

@@ -162,7 +162,7 @@ export const EditorCardMenu = ({
<EllipsisIcon className="h-4 w-4 text-slate-500 hover:text-slate-600" /> <EllipsisIcon className="h-4 w-4 text-slate-500 hover:text-slate-600" />
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent className="border border-slate-200"> <DropdownMenuContent>
<div className="flex flex-col"> <div className="flex flex-col">
{cardType === "question" && ( {cardType === "question" && (
<DropdownMenuSub> <DropdownMenuSub>
@@ -172,13 +172,12 @@ export const EditorCardMenu = ({
Change question type Change question type
</DropdownMenuSubTrigger> </DropdownMenuSubTrigger>
<DropdownMenuSubContent className="ml-2 border border-slate-200 text-slate-600 hover:text-slate-700"> <DropdownMenuSubContent className="ml-2">
{Object.entries(availableQuestionTypes).map(([type, name]) => { {Object.entries(availableQuestionTypes).map(([type, name]) => {
if (type === card.type) return null; if (type === card.type) return null;
return ( return (
<DropdownMenuItem <DropdownMenuItem
key={type} key={type}
className="min-h-8 cursor-pointer"
onClick={() => { onClick={() => {
setChangeToType(type as TSurveyQuestionTypeEnum); setChangeToType(type as TSurveyQuestionTypeEnum);
if ((card as TSurveyQuestion).logic) { if ((card as TSurveyQuestion).logic) {
@@ -187,8 +186,8 @@ export const EditorCardMenu = ({
} }
changeQuestionType(type as TSurveyQuestionTypeEnum); changeQuestionType(type as TSurveyQuestionTypeEnum);
}}> }}
{QUESTIONS_ICON_MAP[type as TSurveyQuestionTypeEnum]} icon={QUESTIONS_ICON_MAP[type as TSurveyQuestionTypeEnum]}>
<span className="ml-2">{name}</span> <span className="ml-2">{name}</span>
</DropdownMenuItem> </DropdownMenuItem>
); );
@@ -198,7 +197,7 @@ export const EditorCardMenu = ({
)} )}
{cardType === "ending" && ( {cardType === "ending" && (
<DropdownMenuItem <DropdownMenuItem
className="flex min-h-8 cursor-pointer justify-between text-slate-600 hover:text-slate-700" className="min-h-8 justify-between"
onClick={(e) => { onClick={(e) => {
e.preventDefault(); e.preventDefault();
addEndingCardBelow(); addEndingCardBelow();
@@ -209,18 +208,16 @@ export const EditorCardMenu = ({
{cardType === "question" && ( {cardType === "question" && (
<DropdownMenuSub> <DropdownMenuSub>
<DropdownMenuSubTrigger <DropdownMenuSubTrigger className="cursor-pointer" onClick={(e) => e.preventDefault()}>
className="cursor-pointer text-sm text-slate-600 hover:text-slate-700"
onClick={(e) => e.preventDefault()}>
Add question below Add question below
</DropdownMenuSubTrigger> </DropdownMenuSubTrigger>
<DropdownMenuSubContent className="ml-4 border border-slate-200"> <DropdownMenuSubContent className="ml-2">
{Object.entries(availableQuestionTypes).map(([type, name]) => { {Object.entries(availableQuestionTypes).map(([type, name]) => {
return ( return (
<DropdownMenuItem <DropdownMenuItem
key={type} key={type}
className="min-h-8 cursor-pointer" className="min-h-8"
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
if (cardType === "question") { if (cardType === "question") {
@@ -236,33 +233,27 @@ export const EditorCardMenu = ({
</DropdownMenuSub> </DropdownMenuSub>
)} )}
<DropdownMenuItem <DropdownMenuItem
className={`flex min-h-8 cursor-pointer justify-between text-slate-600 hover:text-slate-700 ${
cardIdx === 0 ? "opacity-50" : ""
}`}
onClick={(e) => { onClick={(e) => {
if (cardIdx !== 0) { if (cardIdx !== 0) {
e.stopPropagation(); e.stopPropagation();
moveCard(cardIdx, true); moveCard(cardIdx, true);
} }
}} }}
icon={<ArrowUpIcon className="h-4 w-4" />}
disabled={cardIdx === 0}> disabled={cardIdx === 0}>
<span className="text-sm">Move up</span> <span>Move up</span>
<ArrowUpIcon className="h-4 w-4" />
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
className={`flex min-h-8 cursor-pointer justify-between text-slate-600 hover:text-slate-700 ${
lastCard ? "opacity-50" : ""
}`}
onClick={(e) => { onClick={(e) => {
if (!lastCard) { if (!lastCard) {
e.stopPropagation(); e.stopPropagation();
moveCard(cardIdx, false); moveCard(cardIdx, false);
} }
}} }}
icon={<ArrowDownIcon className="h-4 w-4" />}
disabled={lastCard}> disabled={lastCard}>
<span className="text-sm text-slate-600 hover:text-slate-700">Move down</span> <span>Move down</span>
<ArrowDownIcon className="h-4 w-4" />
</DropdownMenuItem> </DropdownMenuItem>
</div> </div>
</DropdownMenuContent> </DropdownMenuContent>

View File

@@ -100,11 +100,11 @@ export const HiddenFieldsCard = ({
className="flex-1 rounded-r-lg border border-slate-200 transition-all duration-300 ease-in-out"> className="flex-1 rounded-r-lg border border-slate-200 transition-all duration-300 ease-in-out">
<Collapsible.CollapsibleTrigger <Collapsible.CollapsibleTrigger
asChild asChild
className="flex cursor-pointer justify-between p-4 hover:bg-slate-50"> className="flex cursor-pointer justify-between rounded-r-lg p-4 hover:bg-slate-50">
<div> <div>
<div className="inline-flex"> <div className="inline-flex">
<div> <div>
<p className="text-sm font-semibold">Hidden Fields</p> <p className="text-sm font-semibold">Hidden fields</p>
</div> </div>
</div> </div>

View File

@@ -200,30 +200,27 @@ export function LogicEditorActions({
<DropdownMenuContent> <DropdownMenuContent>
<DropdownMenuItem <DropdownMenuItem
className="flex items-center gap-2"
onClick={() => { onClick={() => {
handleActionsChange("addBelow", idx); handleActionsChange("addBelow", idx);
}}> }}
<PlusIcon className="h-4 w-4" /> icon={<PlusIcon className="h-4 w-4" />}>
Add action below Add action below
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
className="flex items-center gap-2"
disabled={actions.length === 1} disabled={actions.length === 1}
onClick={() => { onClick={() => {
handleActionsChange("remove", idx); handleActionsChange("remove", idx);
}}> }}
<TrashIcon className="h-4 w-4" /> icon={<TrashIcon className="h-4 w-4" />}>
Remove Remove
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
className="flex items-center gap-2"
onClick={() => { onClick={() => {
handleActionsChange("duplicate", idx); handleActionsChange("duplicate", idx);
}}> }}
<CopyIcon className="h-4 w-4" /> icon={<CopyIcon className="h-4 w-4" />}>
Duplicate Duplicate
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>

View File

@@ -216,18 +216,16 @@ export function LogicEditorConditions({
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent> <DropdownMenuContent>
<DropdownMenuItem <DropdownMenuItem
className="flex items-center gap-2"
onClick={() => { onClick={() => {
handleAddConditionBelow(condition.id); handleAddConditionBelow(condition.id);
}}> }}
<PlusIcon className="h-4 w-4" /> icon={<PlusIcon className="h-4 w-4" />}>
Add condition below Add condition below
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
className="flex items-center gap-2"
disabled={depth === 0 && conditions.conditions.length === 1} disabled={depth === 0 && conditions.conditions.length === 1}
onClick={() => handleRemoveCondition(condition.id)}> onClick={() => handleRemoveCondition(condition.id)}
<TrashIcon className="h-4 w-4" /> icon={<TrashIcon className="h-4 w-4" />}>
Remove Remove
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>
@@ -307,30 +305,26 @@ export function LogicEditorConditions({
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent> <DropdownMenuContent>
<DropdownMenuItem <DropdownMenuItem
className="flex items-center gap-2"
onClick={() => { onClick={() => {
handleAddConditionBelow(condition.id); handleAddConditionBelow(condition.id);
}}> }}
<PlusIcon className="h-4 w-4" /> icon={<PlusIcon className="h-4 w-4" />}>
Add condition below Add condition below
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
className="flex items-center gap-2"
disabled={depth === 0 && conditions.conditions.length === 1} disabled={depth === 0 && conditions.conditions.length === 1}
onClick={() => handleRemoveCondition(condition.id)}> onClick={() => handleRemoveCondition(condition.id)}
<TrashIcon className="h-4 w-4" /> icon={<TrashIcon className="h-4 w-4" />}>
Remove Remove
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
className="flex items-center gap-2" onClick={() => handleDuplicateCondition(condition.id)}
onClick={() => handleDuplicateCondition(condition.id)}> icon={<CopyIcon className="h-4 w-4" />}>
<CopyIcon className="h-4 w-4" />
Duplicate Duplicate
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
className="flex items-center gap-2" onClick={() => handleCreateGroup(condition.id)}
onClick={() => handleCreateGroup(condition.id)}> icon={<WorkflowIcon className="h-4 w-4" />}>
<WorkflowIcon className="h-4 w-4" />
Create group Create group
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>

View File

@@ -48,7 +48,7 @@ export const SurveyVariablesCard = ({
className="flex-1 rounded-r-lg border border-slate-200 transition-all duration-300 ease-in-out"> className="flex-1 rounded-r-lg border border-slate-200 transition-all duration-300 ease-in-out">
<Collapsible.CollapsibleTrigger <Collapsible.CollapsibleTrigger
asChild asChild
className="flex cursor-pointer justify-between p-4 hover:bg-slate-50"> className="flex cursor-pointer justify-between rounded-r-lg p-4 hover:bg-slate-50">
<div> <div>
<div className="inline-flex"> <div className="inline-flex">
<div> <div>

View File

@@ -377,7 +377,6 @@ export const MainNavigation = ({
</div> </div>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent <DropdownMenuContent
className="w-fit space-y-1 rounded-xl border border-slate-200 shadow-sm"
id="userDropdownInnerContentWrapper" id="userDropdownInnerContentWrapper"
side="right" side="right"
sideOffset={10} sideOffset={10}
@@ -389,7 +388,7 @@ export const MainNavigation = ({
{sortedProducts.map((product) => ( {sortedProducts.map((product) => (
<DropdownMenuRadioItem <DropdownMenuRadioItem
value={product.id} value={product.id}
className="cursor-pointer break-all rounded-lg font-normal" className="cursor-pointer break-all"
key={product.id}> key={product.id}>
<div> <div>
{product.config.channel === "website" ? ( {product.config.channel === "website" ? (
@@ -410,8 +409,7 @@ export const MainNavigation = ({
{isOwnerOrAdmin && ( {isOwnerOrAdmin && (
<DropdownMenuItem <DropdownMenuItem
onClick={() => handleAddProduct(organization.id)} onClick={() => handleAddProduct(organization.id)}
className="rounded-lg font-normal"> icon={<PlusIcon className="mr-2 h-4 w-4" />}>
<PlusIcon className="mr-2 h-4 w-4" />
<span>Add product</span> <span>Add product</span>
</DropdownMenuItem> </DropdownMenuItem>
)} )}
@@ -455,7 +453,6 @@ export const MainNavigation = ({
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent <DropdownMenuContent
className="w-56 rounded-xl border border-slate-200 shadow-sm"
id="userDropdownInnerContentWrapper" id="userDropdownInnerContentWrapper"
side="right" side="right"
sideOffset={10} sideOffset={10}
@@ -466,15 +463,9 @@ export const MainNavigation = ({
{dropdownNavigation.map( {dropdownNavigation.map(
(link) => (link) =>
!link.hidden && ( !link.hidden && (
<Link <Link href={link.href} target={link.target} className="flex w-full items-center">
href={link.href} <DropdownMenuItem>
target={link.target} <link.icon className="mr-2 h-4 w-4" strokeWidth={1.5} />
key={link.label}
className="flex items-center">
<DropdownMenuItem
className="w-full gap-x-2 rounded-lg font-normal"
key={link.label}>
<link.icon className="h-4 w-4" strokeWidth={1.5} />
{link.label} {link.label}
</DropdownMenuItem> </DropdownMenuItem>
</Link> </Link>
@@ -484,12 +475,11 @@ export const MainNavigation = ({
{/* Logout */} {/* Logout */}
<DropdownMenuItem <DropdownMenuItem
className="w-full gap-x-2 rounded-lg font-normal"
onClick={async () => { onClick={async () => {
await signOut({ callbackUrl: "/auth/login" }); await signOut({ callbackUrl: "/auth/login" });
await formbricksLogout(); await formbricksLogout();
}}> }}
<LogOutIcon className="h-4 w-4" strokeWidth={1.5} /> icon={<LogOutIcon className="h-4 w-4" strokeWidth={1.5} />}>
Logout Logout
</DropdownMenuItem> </DropdownMenuItem>
@@ -504,10 +494,7 @@ export const MainNavigation = ({
</div> </div>
</DropdownMenuSubTrigger> </DropdownMenuSubTrigger>
<DropdownMenuPortal> <DropdownMenuPortal>
<DropdownMenuSubContent <DropdownMenuSubContent sideOffset={10} alignOffset={5}>
className="rounded-xl border border-slate-200 shadow-sm"
sideOffset={10}
alignOffset={5}>
<DropdownMenuRadioGroup <DropdownMenuRadioGroup
value={currentOrganizationId} value={currentOrganizationId}
onValueChange={(organizationId) => onValueChange={(organizationId) =>
@@ -526,8 +513,7 @@ export const MainNavigation = ({
{isMultiOrgEnabled && ( {isMultiOrgEnabled && (
<DropdownMenuItem <DropdownMenuItem
onClick={() => setShowCreateOrganizationModal(true)} onClick={() => setShowCreateOrganizationModal(true)}
className="rounded-lg"> icon={<PlusIcon className="mr-2 h-4 w-4" />}>
<PlusIcon className="mr-2 h-4 w-4" />
<span>Create new organization</span> <span>Create new organization</span>
</DropdownMenuItem> </DropdownMenuItem>
)} )}

View File

@@ -223,7 +223,6 @@ export const CustomFilter = ({ survey }: CustomFilterProps) => {
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent> <DropdownMenuContent>
<DropdownMenuItem <DropdownMenuItem
className="hover:ring-0"
onClick={() => { onClick={() => {
setFilterRange(FilterDropDownLabels.ALL_TIME); setFilterRange(FilterDropDownLabels.ALL_TIME);
setDateRange({ from: undefined, to: getTodayDate() }); setDateRange({ from: undefined, to: getTodayDate() });
@@ -231,7 +230,6 @@ export const CustomFilter = ({ survey }: CustomFilterProps) => {
<p className="text-slate-700">All time</p> <p className="text-slate-700">All time</p>
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
className="hover:ring-0"
onClick={() => { onClick={() => {
setFilterRange(FilterDropDownLabels.LAST_7_DAYS); setFilterRange(FilterDropDownLabels.LAST_7_DAYS);
setDateRange({ from: startOfDay(subDays(new Date(), 7)), to: getTodayDate() }); setDateRange({ from: startOfDay(subDays(new Date(), 7)), to: getTodayDate() });
@@ -239,7 +237,6 @@ export const CustomFilter = ({ survey }: CustomFilterProps) => {
<p className="text-slate-700">Last 7 days</p> <p className="text-slate-700">Last 7 days</p>
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
className="hover:ring-0"
onClick={() => { onClick={() => {
setFilterRange(FilterDropDownLabels.LAST_30_DAYS); setFilterRange(FilterDropDownLabels.LAST_30_DAYS);
setDateRange({ from: startOfDay(subDays(new Date(), 30)), to: getTodayDate() }); setDateRange({ from: startOfDay(subDays(new Date(), 30)), to: getTodayDate() });
@@ -247,7 +244,6 @@ export const CustomFilter = ({ survey }: CustomFilterProps) => {
<p className="text-slate-700">Last 30 days</p> <p className="text-slate-700">Last 30 days</p>
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
className="hover:ring-0"
onClick={() => { onClick={() => {
setIsDatePickerOpen(true); setIsDatePickerOpen(true);
setFilterRange(FilterDropDownLabels.CUSTOM_RANGE); setFilterRange(FilterDropDownLabels.CUSTOM_RANGE);
@@ -274,28 +270,24 @@ export const CustomFilter = ({ survey }: CustomFilterProps) => {
<DropdownMenuContent align="start"> <DropdownMenuContent align="start">
<DropdownMenuItem <DropdownMenuItem
className="hover:ring-0"
onClick={() => { onClick={() => {
handleDowndloadResponses(FilterDownload.ALL, "csv"); handleDowndloadResponses(FilterDownload.ALL, "csv");
}}> }}>
<p className="text-slate-700">All responses (CSV)</p> <p className="text-slate-700">All responses (CSV)</p>
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
className="hover:ring-0"
onClick={() => { onClick={() => {
handleDowndloadResponses(FilterDownload.ALL, "xlsx"); handleDowndloadResponses(FilterDownload.ALL, "xlsx");
}}> }}>
<p className="text-slate-700">All responses (Excel)</p> <p className="text-slate-700">All responses (Excel)</p>
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
className="hover:ring-0"
onClick={() => { onClick={() => {
handleDowndloadResponses(FilterDownload.FILTER, "csv"); handleDowndloadResponses(FilterDownload.FILTER, "csv");
}}> }}>
<p className="text-slate-700">Current selection (CSV)</p> <p className="text-slate-700">Current selection (CSV)</p>
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
className="hover:ring-0"
onClick={() => { onClick={() => {
handleDowndloadResponses(FilterDownload.FILTER, "xlsx"); handleDowndloadResponses(FilterDownload.FILTER, "xlsx");
}}> }}>

View File

@@ -98,34 +98,29 @@ export const ResultsShareButton = ({ survey, webAppUrl }: ResultsShareButtonProp
<DropdownMenuContent align="start"> <DropdownMenuContent align="start">
{survey.resultShareKey ? ( {survey.resultShareKey ? (
<DropdownMenuItem <DropdownMenuItem
className="hover:ring-0"
onClick={() => { onClick={() => {
navigator.clipboard.writeText(surveyUrl); navigator.clipboard.writeText(surveyUrl);
toast.success("Link to public results copied"); toast.success("Link to public results copied");
}}> }}
<p className="text-slate-700"> icon={<CopyIcon className="ml-1.5 inline h-4 w-4" />}>
Copy link to public results <CopyIcon className="ml-1.5 inline h-4 w-4" /> <p className="text-slate-700">Copy link to public results</p>
</p>
</DropdownMenuItem> </DropdownMenuItem>
) : ( ) : (
<DropdownMenuItem <DropdownMenuItem
className="text-slate-700 hover:ring-0"
onClick={() => { onClick={() => {
copyUrlToClipboard(); copyUrlToClipboard();
}}> }}
<p className="flex items-center text-slate-700"> icon={<CopyIcon className="ml-1.5 h-4 w-4" />}>
Copy link <CopyIcon className="ml-1.5 h-4 w-4" /> <p className="flex items-center text-slate-700">Copy link</p>
</p>
</DropdownMenuItem> </DropdownMenuItem>
)} )}
<DropdownMenuItem <DropdownMenuItem
className="hover:ring-0"
onClick={() => { onClick={() => {
setShowResultsLinkModal(true); setShowResultsLinkModal(true);
}}> }}
icon={<GlobeIcon className="ml-1.5 h-4 w-4" />}>
<p className="flex items-center text-slate-700"> <p className="flex items-center text-slate-700">
{survey.resultShareKey ? "Unpublish from web" : "Publish to web"} {survey.resultShareKey ? "Unpublish from web" : "Publish to web"}
<GlobeIcon className="ml-1.5 h-4 w-4" />
</p> </p>
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>

View File

@@ -247,47 +247,47 @@ test.describe("Multi Language Survey Create", async () => {
await page.getByText("Welcome CardShownOn").click(); await page.getByText("Welcome CardShownOn").click();
// Add questions in default language // Add questions in default language
await page.getByText("Add Question").click(); await page.getByText("Add question").click();
await page.getByRole("button", { name: "Single-Select" }).click(); await page.getByRole("button", { name: "Single-Select" }).click();
await page await page
.locator("div") .locator("div")
.filter({ hasText: /^Add QuestionAdd a new question to your survey$/ }) .filter({ hasText: /^Add questionAdd a new question to your survey$/ })
.nth(1) .nth(1)
.click(); .click();
await page.getByRole("button", { name: "Multi-Select" }).click(); await page.getByRole("button", { name: "Multi-Select" }).click();
await page await page
.locator("div") .locator("div")
.filter({ hasText: /^Add QuestionAdd a new question to your survey$/ }) .filter({ hasText: /^Add questionAdd a new question to your survey$/ })
.nth(1) .nth(1)
.click(); .click();
await page.getByRole("button", { name: "Picture Selection" }).click(); await page.getByRole("button", { name: "Picture Selection" }).click();
await page await page
.locator("div") .locator("div")
.filter({ hasText: /^Add QuestionAdd a new question to your survey$/ }) .filter({ hasText: /^Add questionAdd a new question to your survey$/ })
.nth(1) .nth(1)
.click(); .click();
await page.getByRole("button", { name: "Rating" }).click(); await page.getByRole("button", { name: "Rating" }).click();
await page await page
.locator("div") .locator("div")
.filter({ hasText: /^Add QuestionAdd a new question to your survey$/ }) .filter({ hasText: /^Add questionAdd a new question to your survey$/ })
.nth(1) .nth(1)
.click(); .click();
await page.getByRole("button", { name: "Net Promoter Score (NPS)" }).click(); await page.getByRole("button", { name: "Net Promoter Score (NPS)" }).click();
await page await page
.locator("div") .locator("div")
.filter({ hasText: /^Add QuestionAdd a new question to your survey$/ }) .filter({ hasText: /^Add questionAdd a new question to your survey$/ })
.nth(1) .nth(1)
.click(); .click();
await page.getByRole("button", { name: "Date" }).click(); await page.getByRole("button", { name: "Date" }).click();
await page await page
.locator("div") .locator("div")
.filter({ hasText: /^Add QuestionAdd a new question to your survey$/ }) .filter({ hasText: /^Add questionAdd a new question to your survey$/ })
.nth(1) .nth(1)
.click(); .click();
await page.getByRole("button", { name: "File Upload" }).click(); await page.getByRole("button", { name: "File Upload" }).click();
await page await page
.locator("div") .locator("div")
.filter({ hasText: /^Add QuestionAdd a new question to your survey$/ }) .filter({ hasText: /^Add questionAdd a new question to your survey$/ })
.nth(1) .nth(1)
.click(); .click();
@@ -295,13 +295,13 @@ test.describe("Multi Language Survey Create", async () => {
await page.getByRole("button", { name: "Matrix" }).click(); await page.getByRole("button", { name: "Matrix" }).click();
await page await page
.locator("div") .locator("div")
.filter({ hasText: /^Add QuestionAdd a new question to your survey$/ }) .filter({ hasText: /^Add questionAdd a new question to your survey$/ })
.nth(1) .nth(1)
.click(); .click();
await page.getByRole("button", { name: "Address" }).click(); await page.getByRole("button", { name: "Address" }).click();
await page await page
.locator("div") .locator("div")
.filter({ hasText: /^Add QuestionAdd a new question to your survey$/ }) .filter({ hasText: /^Add questionAdd a new question to your survey$/ })
.nth(1) .nth(1)
.click(); .click();
await page.getByRole("button", { name: "Ranking" }).click(); await page.getByRole("button", { name: "Ranking" }).click();

View File

@@ -136,7 +136,7 @@ export const signupUsingInviteToken = async (page: Page, name: string, email: st
}; };
export const createSurvey = async (page: Page, params: CreateSurveyParams) => { export const createSurvey = async (page: Page, params: CreateSurveyParams) => {
const addQuestion = "Add QuestionAdd a new question to your survey"; const addQuestion = "Add questionAdd a new question to your survey";
await page.getByRole("button", { name: "Start from scratch Create a" }).click(); await page.getByRole("button", { name: "Start from scratch Create a" }).click();
await page.getByRole("button", { name: "Create survey", exact: true }).click(); await page.getByRole("button", { name: "Create survey", exact: true }).click();
@@ -324,7 +324,7 @@ export const createSurvey = async (page: Page, params: CreateSurveyParams) => {
}; };
export const createSurveyWithLogic = async (page: Page, params: CreateSurveyWithLogicParams) => { export const createSurveyWithLogic = async (page: Page, params: CreateSurveyWithLogicParams) => {
const addQuestion = "Add QuestionAdd a new question to your survey"; const addQuestion = "Add questionAdd a new question to your survey";
await page.getByRole("button", { name: "Start from scratch Create a" }).click(); await page.getByRole("button", { name: "Start from scratch Create a" }).click();
await page.getByRole("button", { name: "Create survey", exact: true }).click(); await page.getByRole("button", { name: "Create survey", exact: true }).click();

View File

@@ -1,4 +1,4 @@
import { MoreVertical, Trash2 } from "lucide-react"; import { ArrowDownIcon, ArrowUpIcon, MoreVertical, Trash2 } from "lucide-react";
import { useState } from "react"; import { useState } from "react";
import { cn } from "@formbricks/lib/cn"; import { cn } from "@formbricks/lib/cn";
import { structuredClone } from "@formbricks/lib/pollyfills/structuredClone"; import { structuredClone } from "@formbricks/lib/pollyfills/structuredClone";
@@ -224,7 +224,8 @@ export function SegmentEditor({
<DropdownMenuItem <DropdownMenuItem
onClick={() => { onClick={() => {
handleMoveResource(groupId, "up"); handleMoveResource(groupId, "up");
}}> }}
icon={<ArrowUpIcon className="h-4 w-4" />}>
Move up Move up
</DropdownMenuItem> </DropdownMenuItem>
@@ -232,7 +233,8 @@ export function SegmentEditor({
onClick={() => { onClick={() => {
if (viewOnly) return; if (viewOnly) return;
handleMoveResource(groupId, "down"); handleMoveResource(groupId, "down");
}}> }}
icon={<ArrowDownIcon className="h-4 w-4" />}>
Move down Move down
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>

View File

@@ -1,4 +1,6 @@
import { import {
ArrowDownIcon,
ArrowUpIcon,
FingerprintIcon, FingerprintIcon,
MonitorSmartphoneIcon, MonitorSmartphoneIcon,
MoreVertical, MoreVertical,
@@ -161,13 +163,15 @@ function SegmentFilterItemContextMenu({
<DropdownMenuItem <DropdownMenuItem
onClick={() => { onClick={() => {
onMoveFilter(filterId, "up"); onMoveFilter(filterId, "up");
}}> }}
icon={<ArrowUpIcon className="h-4 w-4" />}>
Move up Move up
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
onClick={() => { onClick={() => {
onMoveFilter(filterId, "down"); onMoveFilter(filterId, "down");
}}> }}
icon={<ArrowDownIcon className="h-4 w-4" />}>
Move down Move down
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>

View File

@@ -190,11 +190,11 @@ export const MultiLanguageCard: FC<MultiLanguageCardProps> = ({
open={open}> open={open}>
<Collapsible.CollapsibleTrigger <Collapsible.CollapsibleTrigger
asChild asChild
className="flex cursor-pointer justify-between p-4 hover:bg-slate-50"> className="flex cursor-pointer justify-between rounded-r-lg p-4 hover:bg-slate-50">
<div> <div>
<div className="inline-flex"> <div className="inline-flex">
<div> <div>
<p className="text-sm font-semibold">Multiple Languages</p> <p className="text-sm font-semibold">Multiple languages</p>
</div> </div>
</div> </div>

View File

@@ -1,4 +1,4 @@
import { EllipsisVerticalIcon, Trash2Icon } from "lucide-react"; import { ArrowDownIcon, ArrowUpIcon, EllipsisVerticalIcon, Trash2Icon } from "lucide-react";
import { cn } from "@formbricks/lib/cn"; import { cn } from "@formbricks/lib/cn";
import { Button } from "../../Button"; import { Button } from "../../Button";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../../DropdownMenu"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../../DropdownMenu";
@@ -24,8 +24,16 @@ export const SegmentFilterItemContextMenu = ({
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent> <DropdownMenuContent>
<DropdownMenuItem onClick={() => onMoveFilter(filterId, "up")}>Move up</DropdownMenuItem> <DropdownMenuItem
<DropdownMenuItem onClick={() => onMoveFilter(filterId, "down")}>Move down</DropdownMenuItem> onClick={() => onMoveFilter(filterId, "up")}
icon={<ArrowUpIcon className="h-4 w-4" />}>
Move up
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => onMoveFilter(filterId, "down")}
icon={<ArrowDownIcon className="h-4 w-4" />}>
Move down
</DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>

View File

@@ -23,15 +23,17 @@ export const ColumnSettingsDropdown = <T,>({
className="capitalize" className="capitalize"
onClick={() => { onClick={() => {
column.toggleVisibility(false); column.toggleVisibility(false);
}}> }}
icon={<EyeOffIcon className="h-4 w-4" />}>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<EyeOffIcon className="h-4 w-4" />
<span>Hide column</span> <span>Hide column</span>
</div> </div>
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem className="capitalize" onClick={() => setIsTableSettingsModalOpen(true)}> <DropdownMenuItem
className="capitalize"
onClick={() => setIsTableSettingsModalOpen(true)}
icon={<SettingsIcon className="h-4 w-4" />}>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<SettingsIcon className="h-4 w-4" />
<span>Table settings</span> <span>Table settings</span>
</div> </div>
</DropdownMenuItem> </DropdownMenuItem>

View File

@@ -29,7 +29,7 @@ const DropdownMenuSubTrigger: React.ComponentType<
<DropdownMenuPrimitive.SubTrigger <DropdownMenuPrimitive.SubTrigger
ref={ref as any} ref={ref as any}
className={cn( className={cn(
"flex cursor-default select-none items-center rounded-md px-2 py-1.5 text-sm font-medium outline-none focus:bg-slate-100 data-[state=open]:bg-slate-100", "flex cursor-default select-none items-center rounded-lg px-2 py-1.5 text-sm font-medium text-slate-600 outline-none hover:text-slate-700 focus:bg-slate-100 data-[state=open]:bg-slate-100",
inset && "pl-8", inset && "pl-8",
className className
)} )}
@@ -46,7 +46,7 @@ const DropdownMenuSubContent: React.ComponentType<DropdownMenuPrimitive.Dropdown
<DropdownMenuPrimitive.SubContent <DropdownMenuPrimitive.SubContent
ref={ref as any} ref={ref as any}
className={cn( className={cn(
"animate-in slide-in-from-left-1 z-50 min-w-[8rem] overflow-hidden rounded-md border border-slate-100 bg-white p-1 text-slate-700 shadow-md", "animate-in slide-in-from-left-1 z-50 min-w-[8rem] overflow-hidden rounded-lg border border-slate-200 bg-white p-1 font-medium text-slate-600 shadow-sm hover:text-slate-700",
className className
)} )}
{...props} {...props}
@@ -67,7 +67,7 @@ const DropdownMenuContent: React.ComponentType<DropdownMenuPrimitive.DropdownMen
ref={ref} ref={ref}
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( className={cn(
"animate-in data-[side=right]:slide-in-from-left-2 data-[side=left]:slide-in-from-right-2 data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] overflow-hidden rounded-md border border-slate-100 bg-white p-1 text-slate-700 shadow-md", "animate-in data-[side=right]:slide-in-from-left-2 data-[side=left]:slide-in-from-right-2 data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] overflow-hidden rounded-lg border border-slate-200 bg-white p-1 font-medium text-slate-700 shadow-sm",
className className
)} )}
{...props} {...props}
@@ -80,22 +80,26 @@ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
const DropdownMenuItem: React.ForwardRefExoticComponent< const DropdownMenuItem: React.ForwardRefExoticComponent<
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
inset?: boolean; inset?: boolean;
icon?: React.ReactNode;
} & React.RefAttributes<React.ElementRef<typeof DropdownMenuPrimitive.Item>> } & React.RefAttributes<React.ElementRef<typeof DropdownMenuPrimitive.Item>>
> = React.forwardRef< > = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Item>, React.ElementRef<typeof DropdownMenuPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
inset?: boolean; inset?: boolean;
icon?: React.ReactNode;
} }
>(({ className, inset, ...props }, ref) => ( >(({ className, children, inset, icon, ...props }, ref) => (
<DropdownMenuPrimitive.Item <DropdownMenuPrimitive.Item
ref={ref} ref={ref}
className={cn( className={cn(
"relative flex cursor-pointer select-none items-center rounded-md px-2 py-1.5 text-sm font-medium outline-none focus:bg-slate-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50", "relative flex w-full cursor-pointer select-none items-center gap-x-2 rounded-lg px-2 py-1.5 text-sm font-medium outline-none focus:bg-slate-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
inset && "pl-8", inset && "pl-8",
className className
)} )}
{...props} {...props}>
/> {icon}
{children}
</DropdownMenuPrimitive.Item>
)); ));
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
@@ -108,7 +112,7 @@ const DropdownMenuCheckboxItem: React.ComponentType<
<DropdownMenuPrimitive.CheckboxItem <DropdownMenuPrimitive.CheckboxItem
ref={ref} ref={ref}
className={cn( className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm font-medium outline-none focus:bg-slate-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50", "relative flex cursor-default select-none items-center rounded-lg py-1.5 pl-8 pr-2 text-sm font-medium outline-none focus:bg-slate-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className className
)} )}
checked={checked} checked={checked}
@@ -132,7 +136,7 @@ const DropdownMenuRadioItem: React.ComponentType<
<DropdownMenuPrimitive.RadioItem <DropdownMenuPrimitive.RadioItem
ref={ref} ref={ref}
className={cn( className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm font-medium outline-none focus:bg-slate-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50", "relative flex cursor-default select-none items-center rounded-lg py-1.5 pl-8 pr-2 text-sm font-medium outline-none focus:bg-slate-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className className
)} )}
{...props}> {...props}>

View File

@@ -35,7 +35,7 @@ export const AddVariablesDropdown: React.FC<IAddVariablesDropdown> = (props) =>
</div> </div>
<div className="h-64 overflow-scroll md:h-80"> <div className="h-64 overflow-scroll md:h-80">
{props.variables.map((variable) => ( {props.variables.map((variable) => (
<DropdownMenuItem key={variable} className="hover:ring-0"> <DropdownMenuItem key={variable}>
<button <button
key={variable} key={variable}
type="button" type="button"

View File

@@ -468,7 +468,7 @@ export const ToolbarPlugin = (props: TextEditorProps) => {
<DropdownMenuContent align="start"> <DropdownMenuContent align="start">
{Object.keys(blockTypeToBlockName).map((key) => { {Object.keys(blockTypeToBlockName).map((key) => {
return ( return (
<DropdownMenuItem key={key} className="outline-none hover:ring-0 focus:ring-0"> <DropdownMenuItem key={key}>
<Button <Button
color="minimal" color="minimal"
type="button" type="button"

View File

@@ -213,7 +213,6 @@ export const RecallItemSelect = ({
setShowRecallItemSelect(false); setShowRecallItemSelect(false);
}} }}
autoFocus={false} autoFocus={false}
className="flex w-full cursor-pointer rounded-md p-2 focus:bg-slate-200 focus:outline-none"
onKeyDown={(e) => { onKeyDown={(e) => {
if (e.key === "ArrowUp" && index === 0) { if (e.key === "ArrowUp" && index === 0) {
document.getElementById("recallItemSearchInput")?.focus(); document.getElementById("recallItemSearchInput")?.focus();