Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: modified google sheet integration and minor refactors in other integrations #2572

Merged
merged 9 commits into from
May 23, 2024
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
"use client";

import { createOrUpdateIntegrationAction } from "@/app/(app)/environments/[environmentId]/integrations/actions";
import { BaseSelectDropdown } from "@/app/(app)/environments/[environmentId]/integrations/airtable/components/BaseSelectDropdown";
import { fetchTables } from "@/app/(app)/environments/[environmentId]/integrations/airtable/lib/airtable";
import AirtableLogo from "@/images/airtableLogo.svg";
import Image from "next/image";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { Control, Controller, UseFormSetValue, useForm } from "react-hook-form";
import { Controller, useForm } from "react-hook-form";
import { toast } from "react-hot-toast";

import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
Expand All @@ -25,8 +27,6 @@ import { Label } from "@formbricks/ui/Label";
import { Modal } from "@formbricks/ui/Modal";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@formbricks/ui/Select";

import AirtableLogo from "../images/airtable.svg";

type EditModeProps =
| { isEditMode: false; defaultData?: never }
| { isEditMode: true; defaultData: IntegrationModalInputs & { index: number } };
Expand All @@ -47,78 +47,25 @@ export type IntegrationModalInputs = {
questions: string[];
};

function NoBaseFoundError() {
const NoBaseFoundError = () => {
return (
<Alert>
<AlertTitle>No Airtable bases found</AlertTitle>
<AlertDescription>Please create a base on Airtable</AlertDescription>
</Alert>
);
}

interface BaseSelectProps {
control: Control<IntegrationModalInputs, any>;
isLoading: boolean;
fetchTable: (val: string) => Promise<void>;
airtableArray: TIntegrationItem[];
setValue: UseFormSetValue<IntegrationModalInputs>;
defaultValue: string | undefined;
}
};

function BaseSelect({
export const AddIntegrationModal = ({
open,
setOpenWithStates,
environmentId,
airtableArray,
control,
fetchTable,
isLoading,
setValue,
defaultValue,
}: BaseSelectProps) {
return (
<div className="flex w-full flex-col">
<Label htmlFor="base">Airtable base</Label>
<div className="mt-1 flex">
<Controller
control={control}
name="base"
render={({ field }) => (
<Select
required
disabled={isLoading}
onValueChange={async (val) => {
field.onChange(val);
await fetchTable(val);
setValue("table", "");
}}
defaultValue={defaultValue}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
{airtableArray.map((item) => (
<SelectItem key={item.id} value={item.id}>
{item.name}
</SelectItem>
))}
</SelectContent>
</Select>
)}
/>
</div>
</div>
);
}

export default function AddIntegrationModal(props: AddIntegrationModalProps) {
const {
open,
setOpenWithStates,
environmentId,
airtableArray,
surveys,
airtableIntegration,
isEditMode,
defaultData,
} = props;
surveys,
airtableIntegration,
isEditMode,
defaultData,
}: AddIntegrationModalProps) => {
const router = useRouter();
const [tables, setTables] = useState<TIntegrationAirtableTables["tables"]>([]);
const [isLoading, setIsLoading] = useState(false);
Expand Down Expand Up @@ -248,7 +195,7 @@ export default function AddIntegrationModal(props: AddIntegrationModalProps) {
<div className="flex rounded-lg p-6">
<div className="flex w-full flex-col gap-y-4 pt-5">
{airtableArray.length ? (
<BaseSelect
<BaseSelectDropdown
control={control}
isLoading={isLoading}
fetchTable={fetchTable}
Expand Down Expand Up @@ -392,4 +339,4 @@ export default function AddIntegrationModal(props: AddIntegrationModalProps) {
</form>
</Modal>
);
}
};
Original file line number Diff line number Diff line change
@@ -1,44 +1,50 @@
"use client";

import { ManageIntegration } from "@/app/(app)/environments/[environmentId]/integrations/airtable/components/ManageIntegration";
import { authorize } from "@/app/(app)/environments/[environmentId]/integrations/airtable/lib/airtable";
import airtableLogo from "@/images/airtableLogo.svg";
import formbricksLogo from "@/images/logo.svg";
import { useState } from "react";

import { TEnvironment } from "@formbricks/types/environment";
import { TIntegrationItem } from "@formbricks/types/integration";
import { TIntegrationAirtable } from "@formbricks/types/integration/airtable";
import { TSurvey } from "@formbricks/types/surveys";

import Connect from "./Connect";
import Home from "./Home";
import { ConnectIntegration } from "@formbricks/ui/ConnectIntegration";

interface AirtableWrapperProps {
environmentId: string;
airtableArray: TIntegrationItem[];
airtableIntegration?: TIntegrationAirtable;
surveys: TSurvey[];
environment: TEnvironment;
enabled: boolean;
isEnabled: boolean;
webAppUrl: string;
}

export default function AirtableWrapper({
export const AirtableWrapper = ({
environmentId,
airtableArray,
airtableIntegration,
surveys,
environment,
enabled,
isEnabled,
webAppUrl,
}: AirtableWrapperProps) {
const [isConnected, setIsConnected_] = useState(
}: AirtableWrapperProps) => {
const [isConnected, setIsConnected] = useState(
airtableIntegration ? airtableIntegration.config?.key : false
);

const setIsConnected = (data: boolean) => {
setIsConnected_(data);
const handleAirtableAuthorization = async () => {
authorize(environmentId, webAppUrl).then((url: string) => {
if (url) {
window.location.replace(url);
}
});
};

return isConnected && airtableIntegration ? (
<Home
<ManageIntegration
airtableArray={airtableArray}
environmentId={environmentId}
environment={environment}
Expand All @@ -47,6 +53,12 @@ export default function AirtableWrapper({
surveys={surveys}
/>
) : (
<Connect enabled={enabled} environmentId={environment.id} webAppUrl={webAppUrl} />
<ConnectIntegration
isEnabled={isEnabled}
integrationType={"airtable"}
handleAuthorization={handleAirtableAuthorization}
integrationLogoSrc={airtableLogo}
formbricksLogoSrc={formbricksLogo}
/>
);
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Control, Controller, UseFormSetValue } from "react-hook-form";

import { TIntegrationItem } from "@formbricks/types/integration";
import { Label } from "@formbricks/ui/Label";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@formbricks/ui/Select";

import { IntegrationModalInputs } from "./AddIntegrationModal";

interface BaseSelectProps {
control: Control<IntegrationModalInputs, any>;
isLoading: boolean;
fetchTable: (val: string) => Promise<void>;
airtableArray: TIntegrationItem[];
setValue: UseFormSetValue<IntegrationModalInputs>;
defaultValue: string | undefined;
}

export const BaseSelectDropdown = ({
airtableArray,
control,
fetchTable,
isLoading,
setValue,
defaultValue,
}: BaseSelectProps) => {
return (
<div className="flex w-full flex-col">
<Label htmlFor="base">Airtable base</Label>
<div className="mt-1 flex">
<Controller
control={control}
name="base"
render={({ field }) => (
<Select
required
disabled={isLoading}
onValueChange={async (val) => {
field.onChange(val);
await fetchTable(val);
setValue("table", "");
}}
defaultValue={defaultValue}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
{airtableArray.map((item) => (
<SelectItem key={item.id} value={item.id}>
{item.name}
</SelectItem>
))}
</SelectContent>
</Select>
)}
/>
</div>
</div>
);
};

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"use client";

import { deleteIntegrationAction } from "@/app/(app)/environments/[environmentId]/integrations/actions";
import AddIntegrationModal, {
import {
AddIntegrationModal,
IntegrationModalInputs,
} from "@/app/(app)/environments/[environmentId]/integrations/airtable/components/AddIntegrationModal";
import { useState } from "react";
Expand All @@ -16,7 +17,7 @@ import { Button } from "@formbricks/ui/Button";
import { DeleteDialog } from "@formbricks/ui/DeleteDialog";
import EmptySpaceFiller from "@formbricks/ui/EmptySpaceFiller";

interface handleModalProps {
interface ManageIntegrationProps {
airtableIntegration: TIntegrationAirtable;
environment: TEnvironment;
environmentId: string;
Expand All @@ -27,7 +28,7 @@ interface handleModalProps {

const tableHeaders = ["Survey", "Table Name", "Questions", "Updated At"];

export default function Home(props: handleModalProps) {
export const ManageIntegration = (props: ManageIntegrationProps) => {
const { airtableIntegration, environment, environmentId, setIsConnected, surveys, airtableArray } = props;
const [isDeleting, setisDeleting] = useState(false);
const [isDeleteIntegrationModalOpen, setIsDeleteIntegrationModalOpen] = useState(false);
Expand Down Expand Up @@ -146,4 +147,4 @@ export default function Home(props: handleModalProps) {
)}
</div>
);
}
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import AirtableWrapper from "@/app/(app)/environments/[environmentId]/integrations/airtable/components/AirtableWrapper";
import { AirtableWrapper } from "@/app/(app)/environments/[environmentId]/integrations/airtable/components/AirtableWrapper";

import { getAirtableTables } from "@formbricks/lib/airtable/service";
import { AIRTABLE_CLIENT_ID, WEBAPP_URL } from "@formbricks/lib/constants";
Expand All @@ -13,7 +13,7 @@ import { PageContentWrapper } from "@formbricks/ui/PageContentWrapper";
import { PageHeader } from "@formbricks/ui/PageHeader";

export default async function Airtable({ params }) {
const enabled = !!AIRTABLE_CLIENT_ID;
const isEnabled = !!AIRTABLE_CLIENT_ID;
const [surveys, integrations, environment] = await Promise.all([
getSurveys(params.environmentId),
getIntegrations(params.environmentId),
Expand Down Expand Up @@ -42,7 +42,7 @@ export default async function Airtable({ params }) {
<PageHeader pageTitle="Airtable Integration" />
<div className="h-[75vh] w-full">
<AirtableWrapper
enabled={enabled}
isEnabled={isEnabled}
airtableIntegration={airtableIntegration}
airtableArray={airtableArray}
environmentId={environment.id}
Expand Down