Skip to content

Commit

Permalink
Merge branch 'main' into snyk-upgrade-cb9acf232477db6dd68b7234f1ceae8b
Browse files Browse the repository at this point in the history
  • Loading branch information
kodiakhq[bot] authored Oct 27, 2023
2 parents 2244ae8 + 71f6bda commit ef3ff41
Show file tree
Hide file tree
Showing 30 changed files with 1,854 additions and 392 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
run: yarn install --frozen-lockfile

- name: Fetch the latest data
run: yarn run mirror-box
run: yarn run fetch-wbw

- name: Cache dependencies
uses: actions/cache@v1
Expand Down
66 changes: 66 additions & 0 deletions __tests__/pages/lbh/[lawFirmSlug].test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React from "react";

import { render, screen } from "@testing-library/react";
import entityGroup from "~/lib/data/law-firms";
import LawFirmPage, {
getStaticPaths,
getStaticProps,
} from "~/pages/lbh/[lawFirmSlug]";

jest.mock("~/lib/data/law-firms");

describe("LawFirmPage", () => {
const [lawFirm] = entityGroup.data;

it("renders the title and the breadcrumbs correctly", () => {
render(<LawFirmPage lawFirm={lawFirm} />);

const lawFirmListBreadcrumbs = screen.getByText(/^lembaga bantuan hukum$/i);
expect(lawFirmListBreadcrumbs).toBeVisible();
expect(lawFirmListBreadcrumbs).toHaveAttribute("href", `/lbh`);

const [lawFirmBreadcrumbs, title] = screen.getAllByText(lawFirm.nama_lbh);
expect(lawFirmBreadcrumbs).toBeVisible();
expect(lawFirmBreadcrumbs).toHaveAttribute("href", `/lbh/${lawFirm.slug}`);

expect(title).toBeVisible();
});
});

describe("getStaticPaths", () => {
it("returns the correct paths", () => {
const paths = entityGroup.data.map((lawFirm) => ({
params: {
lawFirmSlug: lawFirm.slug,
},
}));
expect(getStaticPaths({})).toEqual({
fallback: false,
paths,
});
});
});

describe("getStaticProps", () => {
const [lawFirm] = entityGroup.data;

it("gets the lawFirm from the lawFirmSlug params", () => {
expect(
getStaticProps({
params: { lawFirmSlug: lawFirm.slug },
}),
).toEqual({
props: {
lawFirm,
},
});
});

it("returns undefined only given an empty params", () => {
expect(getStaticProps({})).toEqual({
props: {
lawFirm: undefined,
},
});
});
});
79 changes: 79 additions & 0 deletions __tests__/pages/lbh/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React from "react";

import { render, screen, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import LawFirmsPage, { getStaticProps } from "~/pages/lbh";
import { lawFirmBuilder } from "~/lib/data/__mocks__/builders/law-firms";
import entityGroup from "~/lib/data/law-firms";

jest.mock("~/lib/data/law-firms");
jest.mock("next/router", () => require("next-router-mock"));

describe("LawFirmsPage", () => {
const lawFirm1 = lawFirmBuilder();
const lawFirm2 = lawFirmBuilder();
const lawFirmList = [lawFirm1, lawFirm2];

it("renders the title and the breadcrumbs correctly", () => {
render(<LawFirmsPage lawFirmList={lawFirmList} />);

const [breadcrumbs, title] = screen.getAllByText("Lembaga Bantuan Hukum");

expect(breadcrumbs).toBeVisible();
expect(breadcrumbs).toHaveAttribute("href", "/lbh");
expect(title).toBeVisible();
});

it("renders the law firms list correctly", () => {
render(<LawFirmsPage lawFirmList={lawFirmList} />);

expect(screen.getByText(lawFirm1.nama_lbh)).toBeVisible();

const lbhFirmLink = screen.getByRole("link", {
name: lawFirm1.nama_lbh,
});
expect(lbhFirmLink).toHaveAttribute("href", `/lbh/${lawFirm1.slug}`);

expect(within(lbhFirmLink).getByText(lawFirm1.nama_lbh)).toBeVisible();
});

it("performs the search functionality correctly", async () => {
const aceh = lawFirmBuilder({
overrides: {
nama_lbh: "LBH Aceh",
},
});
const medan = lawFirmBuilder({
overrides: {
nama_lbh: "LBH Medan",
},
});

render(<LawFirmsPage lawFirmList={[aceh, medan]} />);

expect(screen.getByText(aceh.nama_lbh)).toBeVisible();

userEvent.type(
screen.getByRole("textbox", {
name: /cari lembaga bantuan hukum:/i,
}),
medan.nama_lbh,
);
userEvent.click(screen.getByRole("button", { name: /cari/i }));

expect(screen.queryByText(aceh.nama_lbh)).not.toBeInTheDocument();
expect(screen.getByText(medan.nama_lbh)).toBeVisible();
});
});

describe("getStaticProps", () => {
it("transforms entityGroup into lawFirmList props correctly", () => {
// TODO: Do a better test because this test is merely a copy of the implementation
const lawFirmList = entityGroup.data;
expect(getStaticProps({})).toEqual({
props: {
lawFirmList,
},
});
});
});
93 changes: 93 additions & 0 deletions components/law-firm-details.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import clsx from "clsx";
import htmr from "htmr";
import { CopyButton } from "~/components/copy-button";
import { OpenMapButton } from "~/components/open-map-button";
import { LawFirm } from "~/lib/data/law-firms";
import { htmrTransform } from "~/lib/htmr-transformers";
import { isNotEmpty, stripTags } from "~/lib/string-utils";

type LawFirmDetailsProps = {
lawFirm: LawFirm;
};

type DescriptionItemProps = {
label: string;
value?: string;
withCopyButton?: boolean;
withOpenMapButton?: boolean;
withTruncation?: boolean;
};

const DescriptionItem = (props: DescriptionItemProps) => {
const value = isNotEmpty(props.value) ? (props.value as string) : "";

return (
<div className="py-4 px-4 sm:py-5 sm:grid sm:grid-cols-3 sm:gap-4">
<dt className="text-sm font-medium text-gray-500">{props.label}</dt>
<dd className="mt-1 flex text-sm text-gray-900 sm:mt-0 sm:col-span-2">
<span
className={clsx("flex-grow", props.withTruncation ? "truncate" : "")}
>
{htmr(value, { transform: htmrTransform })}
</span>
<div className="flex flex-col items-end space-y-1 flex-none ml-2">
{typeof value == "string" &&
value.length > 0 &&
props.withCopyButton && <CopyButton text={stripTags(value)} />}
{typeof value == "string" &&
value.length > 0 &&
props.withOpenMapButton && (
<OpenMapButton address={stripTags(value)} />
)}
</div>
</dd>
</div>
);
};

export function LawFirmDetails({ lawFirm }: LawFirmDetailsProps) {
return (
<div className="bg-white shadow overflow-hidden rounded-md">
<dl className="divide-y divide-gray-200">
<DescriptionItem label="Nama LBH" value={lawFirm.nama_lbh} />
<DescriptionItem
label="Alamat"
value={lawFirm.alamat}
withCopyButton
withOpenMapButton
/>
<DescriptionItem
label="Kontak"
value={lawFirm.nomor_kontak}
withCopyButton
/>
<DescriptionItem label="Email" value={lawFirm.email} />
<DescriptionItem
label="Website"
value={lawFirm.website}
withTruncation
/>
<DescriptionItem label="Instagram" value={lawFirm.ig} withTruncation />
<DescriptionItem
label="Twitter"
value={lawFirm.twitter}
withTruncation
/>
<DescriptionItem
label="Facebook"
value={lawFirm.facebook}
withTruncation
/>
<DescriptionItem
label="Link Donasi"
value={lawFirm.link_donasi}
withTruncation
/>
<DescriptionItem
label="Status Verifikasi"
value={lawFirm.verifikasi ? "Terverifikasi" : "Belum terverifikasi"}
/>
</dl>
</div>
);
}
105 changes: 105 additions & 0 deletions components/law-firm-list-item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import React from "react";

import { BadgeCheckIcon as BadgeCheckIconUnverified } from "@heroicons/react/outline";
import {
BadgeCheckIcon,
LocationMarkerIcon,
PhoneIcon,
} from "@heroicons/react/solid";
import htmr from "htmr";
import Link from "next/link";
import { CopyButton } from "./copy-button";
import { Badge } from "./ui/badge";
import { OpenMapButton } from "./open-map-button";
import { isNotEmpty, stripTags } from "~/lib/string-utils";
import { htmrTransform } from "~/lib/htmr-transformers";
import { LawFirm } from "~/lib/data/law-firms";

interface LawFirmListItemProps {
lawFirm: LawFirm;
}

function LawFirmListItem({ lawFirm }: LawFirmListItemProps) {
return (
<li>
<div className="px-4 py-4 sm:px-6 relative hover:bg-gray-50">
<div className="flex items-center justify-between">
<Link href={`/lbh/${lawFirm.slug}`}>
<a
className="text-sm font-semibold text-blue-600 truncate block helper-link-cover"
title={lawFirm.nama_lbh}
>
{lawFirm.nama_lbh}
</a>
</Link>
<div className="flex-shrink-0 flex space-x-2">
<Badge color="yellow">Lembaga Bantuan Hukum</Badge>
</div>
</div>
<div className="mt-2 sm:flex sm:justify-between">
<p className="text-sm font-medium text-gray-600 truncate">
{lawFirm.email}
</p>
{lawFirm.verifikasi ? (
<div className="mt-2 mb-3 flex items-center text-xs text-gray-500 sm:my-0">
<BadgeCheckIcon
aria-hidden="true"
className="flex-shrink-0 h-4 w-4 sm:order-2 text-green-400"
/>
<p className="ml-2 mr-1">Terverifikasi</p>
</div>
) : (
<div className="mt-2 mb-3 flex items-center text-xs text-gray-400 sm:my-0">
<BadgeCheckIconUnverified
aria-hidden="true"
className="flex-shrink-0 h-4 w-4 sm:order-2 text-gray-400"
/>
<p className="ml-2 mr-1">Belum terverifkasi</p>
</div>
)}
</div>
{isNotEmpty(lawFirm.nomor_kontak) && (
<div className="mt-2 flex justify-between w-full">
<p className="flex items-center text-sm text-gray-500">
<PhoneIcon
aria-hidden="true"
className="flex-shrink-0 mr-2 h-4 w-4 text-gray-400"
/>
{htmr(lawFirm.nomor_kontak as string, {
transform: htmrTransform,
})}
</p>
{typeof lawFirm.nomor_kontak == "string" && (
<CopyButton text={stripTags(lawFirm.nomor_kontak)} />
)}
</div>
)}
{isNotEmpty(lawFirm.alamat) && (
<div className="mt-2 flex justify-between w-full">
<p className="mt-2 flex items-start text-sm text-gray-500 sm:mt-0">
<LocationMarkerIcon
aria-hidden="true"
className="flex-shrink-0 mr-2 h-4 w-4 text-gray-400"
/>
{htmr(lawFirm.alamat, {
transform: htmrTransform,
})}
</p>
<div className="flex flex-col items-end space-y-1 flex-none ml-2">
{typeof lawFirm.alamat == "string" && (
<CopyButton text={stripTags(lawFirm.alamat)} />
)}
{typeof lawFirm.alamat == "string" && (
<OpenMapButton address={stripTags(lawFirm.alamat)} />
)}
</div>
</div>
)}
</div>
</li>
);
}

const _LawFirmListItem = React.memo(LawFirmListItem);

export { _LawFirmListItem as LawFirmListItem };
Loading

0 comments on commit ef3ff41

Please sign in to comment.