diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/components/ResponsePage.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/components/ResponsePage.tsx index 70c4249463..debad97acd 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/components/ResponsePage.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/components/ResponsePage.tsx @@ -36,6 +36,7 @@ interface ResponsePageProps { attributes: TSurveyPersonAttributes; responsesPerPage: number; membershipRole?: TMembershipRole; + totalResponseCount: number; } const ResponsePage = ({ @@ -49,11 +50,13 @@ const ResponsePage = ({ attributes, responsesPerPage, membershipRole, + totalResponseCount, }: ResponsePageProps) => { const [responseCount, setResponseCount] = useState(null); const [responses, setResponses] = useState([]); const [page, setPage] = useState(1); const [hasMore, setHasMore] = useState(true); + const [isFetchingFirstPage, setFetchingFirstPage] = useState(true); const { selectedFilter, dateRange, resetState } = useResponseFilter(); @@ -95,17 +98,6 @@ const ResponsePage = ({ } }, [searchParams, resetState]); - useEffect(() => { - const fetchInitialResponses = async () => { - const responses = await getResponsesAction(surveyId, 1, responsesPerPage, filters); - if (responses.length < responsesPerPage) { - setHasMore(false); - } - setResponses(responses); - }; - fetchInitialResponses(); - }, [surveyId, filters, responsesPerPage]); - useEffect(() => { const handleResponsesCount = async () => { const responseCount = await getResponseCountAction(surveyId, filters); @@ -114,6 +106,22 @@ const ResponsePage = ({ handleResponsesCount(); }, [filters, surveyId]); + useEffect(() => { + const fetchInitialResponses = async () => { + try { + setFetchingFirstPage(true); + const responses = await getResponsesAction(surveyId, 1, responsesPerPage, filters); + if (responses.length < responsesPerPage) { + setHasMore(false); + } + setResponses(responses); + } finally { + setFetchingFirstPage(false); + } + }; + fetchInitialResponses(); + }, [surveyId, filters, responsesPerPage]); + useEffect(() => { setPage(1); setHasMore(true); @@ -152,6 +160,9 @@ const ResponsePage = ({ hasMore={hasMore} deleteResponse={deleteResponse} updateResponse={updateResponse} + isFetchingFirstPage={isFetchingFirstPage} + responseCount={responseCount} + totalResponseCount={totalResponseCount} /> ); diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/components/ResponseTimeline.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/components/ResponseTimeline.tsx index 1840c3cf0b..3d0d344f46 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/components/ResponseTimeline.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/components/ResponseTimeline.tsx @@ -12,6 +12,7 @@ import { TTag } from "@formbricks/types/tags"; import { TUser } from "@formbricks/types/user"; import EmptySpaceFiller from "@formbricks/ui/EmptySpaceFiller"; import SingleResponseCard from "@formbricks/ui/SingleResponseCard"; +import { SkeletonLoader } from "@formbricks/ui/SkeletonLoader"; interface ResponseTimelineProps { environment: TEnvironment; @@ -24,6 +25,9 @@ interface ResponseTimelineProps { hasMore: boolean; updateResponse: (responseId: string, responses: TResponse) => void; deleteResponse: (responseId: string) => void; + isFetchingFirstPage: boolean; + responseCount: number | null; + totalResponseCount: number; } export default function ResponseTimeline({ @@ -36,6 +40,9 @@ export default function ResponseTimeline({ hasMore, updateResponse, deleteResponse, + isFetchingFirstPage, + responseCount, + totalResponseCount, }: ResponseTimelineProps) { const loadingRef = useRef(null); @@ -69,11 +76,14 @@ export default function ResponseTimeline({
{survey.type === "web" && responses.length === 0 && !environment.widgetSetupCompleted ? ( - ) : responses.length === 0 ? ( + ) : isFetchingFirstPage ? ( + + ) : responseCount === 0 ? ( ) : (
diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/page.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/page.tsx index ecccc28e3f..9060a18fbd 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/page.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/page.tsx @@ -6,7 +6,7 @@ import { RESPONSES_PER_PAGE, WEBAPP_URL } from "@formbricks/lib/constants"; import { getEnvironment } from "@formbricks/lib/environment/service"; import { getMembershipByUserIdTeamId } from "@formbricks/lib/membership/service"; import { getProductByEnvironmentId } from "@formbricks/lib/product/service"; -import { getResponsePersonAttributes } from "@formbricks/lib/response/service"; +import { getResponseCountBySurveyId, getResponsePersonAttributes } from "@formbricks/lib/response/service"; import { getSurvey } from "@formbricks/lib/survey/service"; import { getTagsByEnvironmentId } from "@formbricks/lib/tag/service"; import { getTeamByEnvironmentId } from "@formbricks/lib/team/service"; @@ -47,6 +47,8 @@ export default async function Page({ params }) { const currentUserMembership = await getMembershipByUserIdTeamId(session?.user.id, team.id); + const totalResponseCount = await getResponseCountBySurveyId(params.surveyId); + return ( <> ); diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SummaryList.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SummaryList.tsx index adfd2aa644..09ba60cd3f 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SummaryList.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SummaryList.tsx @@ -9,6 +9,7 @@ import { TSurveySummary } from "@formbricks/types/responses"; import { TSurveyQuestionType } from "@formbricks/types/surveys"; import { TSurvey } from "@formbricks/types/surveys"; import EmptySpaceFiller from "@formbricks/ui/EmptySpaceFiller"; +import { SkeletonLoader } from "@formbricks/ui/SkeletonLoader"; import CTASummary from "./CTASummary"; import DateQuestionSummary from "./DateQuestionSummary"; @@ -23,21 +24,31 @@ interface SummaryListProps { responseCount: number | null; environment: TEnvironment; survey: TSurvey; + fetchingSummary: boolean; + totalResponseCount: number; } -export default function SummaryList({ summary, environment, responseCount, survey }: SummaryListProps) { +export default function SummaryList({ + summary, + environment, + responseCount, + survey, + fetchingSummary, + totalResponseCount, +}: SummaryListProps) { return (
{survey.type === "web" && responseCount === 0 && !environment.widgetSetupCompleted ? ( - ) : !responseCount ? ( + ) : fetchingSummary ? ( + + ) : responseCount === 0 ? ( - ) : !summary.length ? ( - ) : ( summary.map((questionSummary) => { if (questionSummary.type === TSurveyQuestionType.OpenText) { diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SummaryPage.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SummaryPage.tsx index 5e630a6108..d825a735f3 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SummaryPage.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SummaryPage.tsx @@ -52,6 +52,7 @@ interface SummaryPageProps { environmentTags: TTag[]; attributes: TSurveyPersonAttributes; membershipRole?: TMembershipRole; + totalResponseCount: number; } const SummaryPage = ({ @@ -64,11 +65,13 @@ const SummaryPage = ({ environmentTags, attributes, membershipRole, + totalResponseCount, }: SummaryPageProps) => { const [responseCount, setResponseCount] = useState(null); const { selectedFilter, dateRange, resetState } = useResponseFilter(); const [surveySummary, setSurveySummary] = useState(initialSurveySummary); const [showDropOffs, setShowDropOffs] = useState(false); + const [isFetchingSummary, setFetchingSummary] = useState(true); const filters = useMemo( () => getFormattedFilters(survey, selectedFilter, dateRange), @@ -77,14 +80,19 @@ const SummaryPage = ({ useEffect(() => { const handleInitialData = async () => { - const responseCount = await getResponseCountAction(surveyId, filters); - setResponseCount(responseCount); - if (responseCount === 0) { - setSurveySummary(initialSurveySummary); - return; + try { + setFetchingSummary(true); + const responseCount = await getResponseCountAction(surveyId, filters); + setResponseCount(responseCount); + if (responseCount === 0) { + setSurveySummary(initialSurveySummary); + return; + } + const response = await getSurveySummaryAction(surveyId, filters); + setSurveySummary(response); + } finally { + setFetchingSummary(false); } - const response = await getSurveySummaryAction(surveyId, filters); - setSurveySummary(response); }; handleInitialData(); @@ -135,6 +143,8 @@ const SummaryPage = ({ responseCount={responseCount} survey={survey} environment={environment} + fetchingSummary={isFetchingSummary} + totalResponseCount={totalResponseCount} /> ); diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/page.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/page.tsx index 5bc3d477a2..e0ef68cc12 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/page.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/page.tsx @@ -7,7 +7,7 @@ import { WEBAPP_URL } from "@formbricks/lib/constants"; import { getEnvironment } from "@formbricks/lib/environment/service"; import { getMembershipByUserIdTeamId } from "@formbricks/lib/membership/service"; import { getProductByEnvironmentId } from "@formbricks/lib/product/service"; -import { getResponsePersonAttributes } from "@formbricks/lib/response/service"; +import { getResponseCountBySurveyId, getResponsePersonAttributes } from "@formbricks/lib/response/service"; import { getSurvey } from "@formbricks/lib/survey/service"; import { getTagsByEnvironmentId } from "@formbricks/lib/tag/service"; import { getTeamByEnvironmentId } from "@formbricks/lib/team/service"; @@ -55,6 +55,7 @@ export default async function Page({ params }) { const tags = await getTagsByEnvironmentId(params.environmentId); const attributes = await getResponsePersonAttributes(params.surveyId); + const totalResponseCount = await getResponseCountBySurveyId(params.surveyId); return ( <> @@ -68,6 +69,7 @@ export default async function Page({ params }) { environmentTags={tags} attributes={attributes} membershipRole={currentUserMembership?.role} + totalResponseCount={totalResponseCount} /> ); diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/components/QuestionFilterComboBox.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/components/QuestionFilterComboBox.tsx index 225918d369..89e3b2b0ef 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/components/QuestionFilterComboBox.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/components/QuestionFilterComboBox.tsx @@ -53,7 +53,12 @@ const QuestionFilterComboBox = ({ // when question type is multi selection so we remove the option from the options which has been already selected const options = isMultiple - ? filterComboBoxOptions?.filter((o) => !filterComboBoxValue?.includes(o)) + ? filterComboBoxOptions?.filter( + (o) => + !filterComboBoxValue?.includes( + typeof o === "object" ? getLocalizedValue(o, defaultLanguageCode) : o + ) + ) : filterComboBoxOptions; // disable the combo box for selection of value when question type is nps or rating and selected value is submitted or skipped diff --git a/apps/web/app/lib/surveys/surveys.ts b/apps/web/app/lib/surveys/surveys.ts index ca9a442deb..01884daab4 100644 --- a/apps/web/app/lib/surveys/surveys.ts +++ b/apps/web/app/lib/surveys/surveys.ts @@ -71,7 +71,9 @@ export const generateQuestionAndFilterOptions = ( questionFilterOptions.push({ type: q.type, filterOptions: conditionOptions[q.type], - filterComboBoxOptions: q?.choices ? q?.choices?.map((c) => c?.label) : [""], + filterComboBoxOptions: q?.choices + ? q?.choices?.filter((c) => c.id !== "other")?.map((c) => c?.label) + : [""], id: q.id, }); } else if (q.type === TSurveyQuestionType.PictureSelection) { diff --git a/apps/web/app/share/[sharingKey]/(analysis)/responses/components/ResponsePage.tsx b/apps/web/app/share/[sharingKey]/(analysis)/responses/components/ResponsePage.tsx index 93e856b22c..b66d863faf 100644 --- a/apps/web/app/share/[sharingKey]/(analysis)/responses/components/ResponsePage.tsx +++ b/apps/web/app/share/[sharingKey]/(analysis)/responses/components/ResponsePage.tsx @@ -31,6 +31,7 @@ interface ResponsePageProps { environmentTags: TTag[]; attributes: TSurveyPersonAttributes; responsesPerPage: number; + totalResponseCount: number; } const ResponsePage = ({ @@ -42,11 +43,13 @@ const ResponsePage = ({ environmentTags, attributes, responsesPerPage, + totalResponseCount, }: ResponsePageProps) => { const [responses, setResponses] = useState([]); const [page, setPage] = useState(1); const [hasMore, setHasMore] = useState(true); const [responseCount, setResponseCount] = useState(null); + const [isFetchingFirstPage, setFetchingFirstPage] = useState(true); const { selectedFilter, dateRange, resetState } = useResponseFilter(); @@ -82,17 +85,6 @@ const ResponsePage = ({ } }, [searchParams, resetState]); - useEffect(() => { - const fetchInitialResponses = async () => { - const responses = await getResponsesBySurveySharingKeyAction(sharingKey, 1, responsesPerPage, filters); - if (responses.length < responsesPerPage) { - setHasMore(false); - } - setResponses(responses); - }; - fetchInitialResponses(); - }, [filters, responsesPerPage, sharingKey]); - useEffect(() => { const handleResponsesCount = async () => { const responseCount = await getResponseCountBySurveySharingKeyAction(sharingKey, filters); @@ -101,6 +93,27 @@ const ResponsePage = ({ handleResponsesCount(); }, [filters, sharingKey]); + useEffect(() => { + const fetchInitialResponses = async () => { + try { + setFetchingFirstPage(true); + const responses = await getResponsesBySurveySharingKeyAction( + sharingKey, + 1, + responsesPerPage, + filters + ); + if (responses.length < responsesPerPage) { + setHasMore(false); + } + setResponses(responses); + } finally { + setFetchingFirstPage(false); + } + }; + fetchInitialResponses(); + }, [filters, responsesPerPage, sharingKey]); + return ( @@ -120,6 +133,9 @@ const ResponsePage = ({ environmentTags={environmentTags} fetchNextPage={fetchNextPage} hasMore={hasMore} + isFetchingFirstPage={isFetchingFirstPage} + responseCount={responseCount} + totalResponseCount={totalResponseCount} /> ); diff --git a/apps/web/app/share/[sharingKey]/(analysis)/responses/components/ResponseTimeline.tsx b/apps/web/app/share/[sharingKey]/(analysis)/responses/components/ResponseTimeline.tsx index c4d7a869b9..0d44f72a33 100644 --- a/apps/web/app/share/[sharingKey]/(analysis)/responses/components/ResponseTimeline.tsx +++ b/apps/web/app/share/[sharingKey]/(analysis)/responses/components/ResponseTimeline.tsx @@ -11,6 +11,7 @@ import { TSurvey } from "@formbricks/types/surveys"; import { TTag } from "@formbricks/types/tags"; import EmptySpaceFiller from "@formbricks/ui/EmptySpaceFiller"; import SingleResponseCard from "@formbricks/ui/SingleResponseCard"; +import { SkeletonLoader } from "@formbricks/ui/SkeletonLoader"; interface ResponseTimelineProps { environment: TEnvironment; @@ -20,6 +21,9 @@ interface ResponseTimelineProps { environmentTags: TTag[]; fetchNextPage: () => void; hasMore: boolean; + isFetchingFirstPage: boolean; + responseCount: number | null; + totalResponseCount: number; } export default function ResponseTimeline({ @@ -29,6 +33,9 @@ export default function ResponseTimeline({ environmentTags, fetchNextPage, hasMore, + isFetchingFirstPage, + responseCount, + totalResponseCount, }: ResponseTimelineProps) { const loadingRef = useRef(null); @@ -62,11 +69,14 @@ export default function ResponseTimeline({
{survey.type === "web" && responses.length === 0 && !environment.widgetSetupCompleted ? ( - ) : responses.length === 0 ? ( + ) : isFetchingFirstPage ? ( + + ) : responseCount === 0 ? ( ) : (
diff --git a/apps/web/app/share/[sharingKey]/(analysis)/responses/page.tsx b/apps/web/app/share/[sharingKey]/(analysis)/responses/page.tsx index 1f4d8f9810..df69bb2a57 100644 --- a/apps/web/app/share/[sharingKey]/(analysis)/responses/page.tsx +++ b/apps/web/app/share/[sharingKey]/(analysis)/responses/page.tsx @@ -4,7 +4,7 @@ import { notFound } from "next/navigation"; import { RESPONSES_PER_PAGE, REVALIDATION_INTERVAL, WEBAPP_URL } from "@formbricks/lib/constants"; import { getEnvironment } from "@formbricks/lib/environment/service"; import { getProductByEnvironmentId } from "@formbricks/lib/product/service"; -import { getResponsePersonAttributes } from "@formbricks/lib/response/service"; +import { getResponseCountBySurveyId, getResponsePersonAttributes } from "@formbricks/lib/response/service"; import { getSurvey, getSurveyIdByResultShareKey } from "@formbricks/lib/survey/service"; import { getTagsByEnvironmentId } from "@formbricks/lib/tag/service"; @@ -35,6 +35,7 @@ export default async function Page({ params }) { const tags = await getTagsByEnvironmentId(environment.id); const attributes = await getResponsePersonAttributes(surveyId); + const totalResponseCount = await getResponseCountBySurveyId(surveyId); return ( <> @@ -48,6 +49,7 @@ export default async function Page({ params }) { environmentTags={tags} attributes={attributes} responsesPerPage={RESPONSES_PER_PAGE} + totalResponseCount={totalResponseCount} /> ); diff --git a/apps/web/app/share/[sharingKey]/(analysis)/summary/components/SummaryPage.tsx b/apps/web/app/share/[sharingKey]/(analysis)/summary/components/SummaryPage.tsx index adb5700240..3268a39ec3 100644 --- a/apps/web/app/share/[sharingKey]/(analysis)/summary/components/SummaryPage.tsx +++ b/apps/web/app/share/[sharingKey]/(analysis)/summary/components/SummaryPage.tsx @@ -46,6 +46,7 @@ interface SummaryPageProps { sharingKey: string; environmentTags: TTag[]; attributes: TSurveyPersonAttributes; + totalResponseCount: number; } const SummaryPage = ({ @@ -56,12 +57,15 @@ const SummaryPage = ({ sharingKey, environmentTags, attributes, + totalResponseCount, }: SummaryPageProps) => { const [responseCount, setResponseCount] = useState(null); - const { selectedFilter, dateRange, resetState } = useResponseFilter(); const [surveySummary, setSurveySummary] = useState(initialSurveySummary); const [showDropOffs, setShowDropOffs] = useState(false); + const [isFetchingSummary, setFetchingSummary] = useState(true); + + const { selectedFilter, dateRange, resetState } = useResponseFilter(); const filters = useMemo( () => getFormattedFilters(survey, selectedFilter, dateRange), @@ -70,14 +74,19 @@ const SummaryPage = ({ useEffect(() => { const handleInitialData = async () => { - const responseCount = await getResponseCountBySurveySharingKeyAction(sharingKey, filters); - setResponseCount(responseCount); - if (responseCount === 0) { - setSurveySummary(initialSurveySummary); - return; + try { + setFetchingSummary(true); + const responseCount = await getResponseCountBySurveySharingKeyAction(sharingKey, filters); + setResponseCount(responseCount); + if (responseCount === 0) { + setSurveySummary(initialSurveySummary); + return; + } + const response = await getSummaryBySurveySharingKeyAction(sharingKey, filters); + setSurveySummary(response); + } finally { + setFetchingSummary(false); } - const response = await getSummaryBySurveySharingKeyAction(sharingKey, filters); - setSurveySummary(response); }; handleInitialData(); @@ -119,6 +128,8 @@ const SummaryPage = ({ responseCount={responseCount} survey={survey} environment={environment} + fetchingSummary={isFetchingSummary} + totalResponseCount={totalResponseCount} /> ); diff --git a/apps/web/app/share/[sharingKey]/(analysis)/summary/page.tsx b/apps/web/app/share/[sharingKey]/(analysis)/summary/page.tsx index 7b1395705a..d11eafb7ed 100644 --- a/apps/web/app/share/[sharingKey]/(analysis)/summary/page.tsx +++ b/apps/web/app/share/[sharingKey]/(analysis)/summary/page.tsx @@ -4,7 +4,7 @@ import { notFound } from "next/navigation"; import { REVALIDATION_INTERVAL } from "@formbricks/lib/constants"; import { getEnvironment } from "@formbricks/lib/environment/service"; import { getProductByEnvironmentId } from "@formbricks/lib/product/service"; -import { getResponsePersonAttributes } from "@formbricks/lib/response/service"; +import { getResponseCountBySurveyId, getResponsePersonAttributes } from "@formbricks/lib/response/service"; import { getSurvey, getSurveyIdByResultShareKey } from "@formbricks/lib/survey/service"; import { getTagsByEnvironmentId } from "@formbricks/lib/tag/service"; @@ -35,6 +35,7 @@ export default async function Page({ params }) { const tags = await getTagsByEnvironmentId(environment.id); const attributes = await getResponsePersonAttributes(surveyId); + const totalResponseCount = await getResponseCountBySurveyId(surveyId); return ( <> @@ -46,6 +47,7 @@ export default async function Page({ params }) { product={product} environmentTags={tags} attributes={attributes} + totalResponseCount={totalResponseCount} /> ); diff --git a/packages/ui/EmptySpaceFiller/index.tsx b/packages/ui/EmptySpaceFiller/index.tsx index 7727d1e709..815f0ff639 100644 --- a/packages/ui/EmptySpaceFiller/index.tsx +++ b/packages/ui/EmptySpaceFiller/index.tsx @@ -67,7 +67,9 @@ const EmptySpaceFiller: React.FC = ({ )} {(environment.widgetSetupCompleted || noWidgetRequired) && ( - Waiting for a response 🧘‍♂️ + + {emptyMessage ?? "Waiting for a response"} 🧘‍♂️ + )}
diff --git a/packages/ui/SkeletonLoader/index.tsx b/packages/ui/SkeletonLoader/index.tsx new file mode 100644 index 0000000000..833c6deb90 --- /dev/null +++ b/packages/ui/SkeletonLoader/index.tsx @@ -0,0 +1,43 @@ +import { Skeleton } from "../Skeleton"; + +type SkeletonLoaderProps = { + type: "response" | "summary"; +}; + +export function SkeletonLoader({ type }: SkeletonLoaderProps) { + if (type === "summary") { + return ( +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ ); + } + + if (type === "response") { + return ( +
+
+ + +
+
+ + + +
+
+ ); + } +}