Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions api/src/controllers/iframe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,9 +236,9 @@ const buildMissionFilters = (
}
}

const organizationNames = normalizeToArray(query.organization);
if (organizationNames?.length) {
filters.organizationName = organizationNames;
const organizationClientIds = normalizeToArray(query.organization);
if (organizationClientIds?.length) {
filters.organizationClientId = organizationClientIds;
}

const actions = normalizeToArray(query.action);
Expand Down
17 changes: 11 additions & 6 deletions api/src/services/widget-mission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { MissionRecord, MissionSearchFilters, MissionSelect } from "@/types
import { buildWhere, missionService } from "./mission";
import publisherOrganizationService from "./publisher-organization";

type Bucket = { key: string; doc_count: number };
type Bucket = { key: string; doc_count: number; label?: string };

type PublisherOrganizationTuple = {
publisherId: string;
Expand Down Expand Up @@ -40,7 +40,7 @@ const buildWidgetWhere = (widget: WidgetRecord, filters: MissionSearchFilters):
const isPlainObject = (value: unknown): value is Record<string, unknown> => typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date);

/**
* Builds a mission condition from `(publisherId, organizationClientId)` tuples.
* Builds a mission condition from `(publisherId, clientId)` tuples.
* Returns either one condition or an `OR` of conditions; empty input matches nothing.
*/
const buildMissionConditionFromPublisherOrganizationTuples = (tuples: PublisherOrganizationTuple[]): Prisma.MissionWhereInput => {
Expand All @@ -58,7 +58,7 @@ const buildMissionConditionFromPublisherOrganizationTuples = (tuples: PublisherO

const conditions = Array.from(byPublisher.entries()).map(([publisherId, clientIds]) => ({
publisherId,
organizationClientId: { in: Array.from(clientIds) },
publisherOrganization: { clientId: { in: Array.from(clientIds) } },
}));

return conditions.length === 1 ? conditions[0] : { OR: conditions };
Expand Down Expand Up @@ -221,9 +221,14 @@ const aggregateWidgetAggs = async (
const formatOrganization = async () => {
const orgRows = await aggregateMissionField("publisherOrganizationId");
const orgIds = orgRows.map((row) => row.key);
const orgs = orgIds.length ? await publisherOrganizationService.findMany({ ids: orgIds }, { select: { id: true, name: true } }) : [];
const orgById = new Map(orgs.map((org) => [org.id, org.name ?? ""]));
return orgRows.map((row) => ({ key: orgById.get(row.key) ?? "", doc_count: row.doc_count })).filter((row) => row.key);
const orgs = orgIds.length ? await publisherOrganizationService.findMany({ ids: orgIds }, { select: { id: true, name: true, clientId: true } }) : [];
const orgById = new Map(orgs.map((org) => [org.id, { name: org.name ?? "", clientId: org.clientId ?? "" }]));
return orgRows
.map((row) => {
const org = orgById.get(row.key);
return { key: org?.clientId ?? "", doc_count: row.doc_count, label: org?.name ?? "" };
})
.filter((row) => row.key);
};

const result: any = {};
Expand Down
10 changes: 5 additions & 5 deletions api/tests/integration/api/iframe/search.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,17 +201,17 @@ describe("GET /iframe/:id/search", () => {
expect(response.body.data[0].title).toContain("Environnement");
});

it("should filter by organization name", async () => {
const response = await request(app).get(`/iframe/${widget.id}/search`).query({ organization: "Green Org" }).expect(200);
it("should filter by organization client ID", async () => {
const response = await request(app).get(`/iframe/${widget.id}/search`).query({ organization: "green-org-1" }).expect(200);

expect(response.body.ok).toBe(true);
expect(response.body.total).toBeGreaterThanOrEqual(0);
expect(response.body.total).toBe(1);
});

it("should support multiple organization names", async () => {
it("should support multiple organization client IDs", async () => {
const response = await request(app)
.get(`/iframe/${widget.id}/search`)
.query({ organization: ["Green Org", "Edu Org"] })
.query({ organization: ["green-org-1", "edu-org-1"] })
.expect(200);

expect(response.body.total).toBe(2);
Expand Down
6 changes: 3 additions & 3 deletions widget/components/ComboxFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { usePlausible } from "next-plausible";
import { useEffect, useRef, useState } from "react";
import { RiArrowDownSLine, RiCheckFill, RiSearchLine } from "react-icons/ri";

import useStore from "@/utils/store";
import { FilterOption } from "@/types";
import useStore from "@/utils/store";

interface ComboboxFilterProps {
options: FilterOption[];
Expand Down Expand Up @@ -120,7 +120,7 @@ const ComboboxFilter = ({
};

return (
<div className="relative w-full min-w-[6rem]" ref={ref}>
<div className="relative w-full min-w-24" ref={ref}>
<label htmlFor={id} className="sr-only">
{placeholder}
</label>
Expand All @@ -131,7 +131,7 @@ const ComboboxFilter = ({
id={id}
aria-label={placeholder}
aria-expanded={show}
className={`select relative truncate text-left ${!values || values.length === 0 ? "!text-[#666666]" : ""}`}
className={`select relative truncate text-left ${!values || values.length === 0 ? "text-[#666666]!" : ""}`}
onClick={() => setShow(!show)}
onKeyDown={handleButtonKeyDown}
>
Expand Down
2 changes: 1 addition & 1 deletion widget/components/FiltersBenevolat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const FiltersBenevolat = ({ widget, apiUrl, values, total, onChange, show, onSho
const remote = data.remote.filter((b) => b.key === "full" || b.key === "possible");
const presentiel = data.remote.filter((b) => b.key === "no");
const newOptions: FilterOptions = {
organizations: data.organization.map((b) => ({ value: b.key, count: b.doc_count, label: b.key })),
organizations: data.organization.map((b) => ({ value: b.key, count: b.doc_count, label: b.label || b.key })),
domains: data.domain.map((b) => ({ value: b.key, count: b.doc_count, label: DOMAINS[b.key] ? DOMAINS[b.key].label : b.key })),
departments: data.department.map((b) => ({
value: b.key === "" ? "none" : b.key,
Expand Down
2 changes: 1 addition & 1 deletion widget/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/types/routes.d.ts";
import "./.next/dev/types/routes.d.ts";

// NOTE: This file should not be edited
// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information.
1 change: 1 addition & 0 deletions widget/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ export interface ApiResponse<T = any> {
export interface AggregationBucket {
key: string;
doc_count: number;
label?: string;
}

export interface AggregationData {
Expand Down