diff --git a/components/province-list.tsx b/components/province-list.tsx
new file mode 100644
index 000000000..c590d7537
--- /dev/null
+++ b/components/province-list.tsx
@@ -0,0 +1,39 @@
+import Link from "next/link";
+
+export type ProvinceListItem = {
+ initials: string;
+ name: string;
+ slug: string;
+ count: number;
+};
+
+type ProvinceListProps = {
+ data: ProvinceListItem[];
+};
+
+export function ProvinceList(props: ProvinceListProps) {
+ return (
+
+ );
+}
diff --git a/components/search-form.tsx b/components/search-form.tsx
new file mode 100644
index 000000000..856110f8b
--- /dev/null
+++ b/components/search-form.tsx
@@ -0,0 +1,39 @@
+interface FormElements extends HTMLFormControlsCollection {
+ keywordsInput: HTMLInputElement;
+}
+
+interface UsernameFormElement extends HTMLFormElement {
+ readonly elements: FormElements;
+}
+
+export function SearchForm({
+ itemName,
+ onSubmitKeywords,
+}: {
+ itemName: string;
+ onSubmitKeywords: (keywords: string) => void;
+}) {
+ function handleSubmit(event: React.FormEvent
) {
+ event.preventDefault();
+ onSubmitKeywords(event.currentTarget.elements.keywordsInput.value);
+ }
+
+ return (
+
+ );
+}
diff --git a/lib/hooks/use-search.ts b/lib/hooks/use-search.ts
new file mode 100644
index 000000000..be90226f2
--- /dev/null
+++ b/lib/hooks/use-search.ts
@@ -0,0 +1,27 @@
+import { useState } from "react";
+
+export function useSearch(items: T[], fieldNames: string[]) {
+ const [filteredItems, setFilteredItems] = useState(items);
+ const handleSubmitKeywords = (keywords: string) => {
+ const lowerKeywords = keywords.toLowerCase();
+ setFilteredItems(
+ items.filter((item) => {
+ const filterBy = (fieldName: keyof T) => {
+ const selectedField = item[fieldName];
+
+ if (typeof selectedField === "string") {
+ return selectedField.toLowerCase().includes(lowerKeywords);
+ } else {
+ return false;
+ }
+ };
+
+ const filterFunctions = fieldNames.map((fieldName) =>
+ filterBy(fieldName as keyof T)
+ );
+ return filterFunctions.reduce((acc, curr) => acc || curr, false);
+ })
+ );
+ };
+ return [filteredItems, handleSubmitKeywords] as const;
+}
diff --git a/lib/database.ts b/lib/provinces.ts
similarity index 84%
rename from lib/database.ts
rename to lib/provinces.ts
index 677462c21..d0b6812ca 100644
--- a/lib/database.ts
+++ b/lib/provinces.ts
@@ -1,7 +1,7 @@
-import database from "../data/wbw-sheets.json";
+import provinces from "../data/wbw-sheets.json";
import { getSlug } from "./string-utils";
-export type Database = Province[];
+export type Provinces = Province[];
export type Province = {
readonly id: number;
@@ -29,7 +29,7 @@ export type ProvincePath = {
};
export const getProvincesPaths = (): ProvincePath[] =>
- database.map((item, index) => {
+ provinces.map((item, index) => {
const provinceSlug = getSlug(item.name, index);
return {
params: { provinceSlug },
@@ -45,7 +45,7 @@ export type ContactPath = {
export const getContactsPaths = (): ContactPath[] => {
const contactsPaths: ContactPath[] = [];
- database.forEach((province, provinceIndex) => {
+ provinces.forEach((province, provinceIndex) => {
province.data.forEach((_, contactIndex) => {
const provinceSlug = getSlug(province.name, provinceIndex);
contactsPaths.push({
@@ -56,4 +56,4 @@ export const getContactsPaths = (): ContactPath[] => {
return contactsPaths;
};
-export default database as unknown as Database;
+export default provinces as unknown as Provinces;
diff --git a/pages/database/index.tsx b/pages/database/index.tsx
deleted file mode 100644
index e889e2793..000000000
--- a/pages/database/index.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-/* This example requires Tailwind CSS v2.0+ */
-import { DotsVerticalIcon } from "@heroicons/react/solid";
-import { GetStaticProps } from "next";
-import database from "../../lib/database";
-import { getInitial, getSlug } from "../../lib/string-utils";
-import Link from "next/link";
-
-type ProvinceListItem = {
- initials: string;
- name: string;
- slug: string;
- count: number;
-};
-
-type DatabasePageProps = {
- provinces: ProvinceListItem[];
-};
-
-export default function DatabasePage(props: DatabasePageProps) {
- return (
-
-
- Daftar Provinsi
-
-
-
- );
-}
-
-export const getStaticProps: GetStaticProps = () => {
- const provinces = database.map(({ name, data }, index) => ({
- initials: getInitial(name),
- name,
- slug: getSlug(name, index),
- count: data.length,
- }));
- provinces.shift();
- return {
- props: {
- provinces,
- },
- };
-};
diff --git a/pages/database/[provinceSlug]/[contactSlug].tsx b/pages/provinces/[provinceSlug]/[contactSlug].tsx
similarity index 87%
rename from pages/database/[provinceSlug]/[contactSlug].tsx
rename to pages/provinces/[provinceSlug]/[contactSlug].tsx
index 5eab0d050..465c6aba6 100644
--- a/pages/database/[provinceSlug]/[contactSlug].tsx
+++ b/pages/provinces/[provinceSlug]/[contactSlug].tsx
@@ -1,6 +1,6 @@
import { GetStaticPaths, GetStaticProps } from "next";
import { ContactDetails } from "../../../components/contact-details";
-import database, { getContactsPaths, Contact } from "../../../lib/database";
+import provinces, { getContactsPaths, Contact } from "../../../lib/provinces";
import { getTheLastSegmentFromKebabCase } from "../../../lib/string-utils";
type ContactPageProps = {
@@ -26,7 +26,7 @@ export const getStaticPaths: GetStaticPaths = () => {
export const getStaticProps: GetStaticProps = ({ params = {} }) => {
const { provinceSlug, contactSlug } = params;
const index = getTheLastSegmentFromKebabCase(provinceSlug as string);
- const province = index ? database[index as unknown as number] : null;
+ const province = index ? provinces[index as unknown as number] : null;
const provinceName = province ? province.name : "";
const contact =
province !== null ? province.data[contactSlug as unknown as number] : null;
diff --git a/pages/database/[provinceSlug]/index.tsx b/pages/provinces/[provinceSlug]/index.tsx
similarity index 52%
rename from pages/database/[provinceSlug]/index.tsx
rename to pages/provinces/[provinceSlug]/index.tsx
index 02d8708e6..2aceabde8 100644
--- a/pages/database/[provinceSlug]/index.tsx
+++ b/pages/provinces/[provinceSlug]/index.tsx
@@ -1,21 +1,42 @@
import { GetStaticPaths, GetStaticProps } from "next";
import { ContactList } from "../../../components/contact-list";
-import database, { getProvincesPaths, Province } from "../../../lib/database";
+import { SearchForm } from "../../../components/search-form";
+import { useSearch } from "../../../lib/hooks/use-search";
+import provinces, {
+ Contact,
+ getProvincesPaths,
+ Province,
+} from "../../../lib/provinces";
import { getTheLastSegmentFromKebabCase } from "../../../lib/string-utils";
-type ProvinceDatabaseProps = {
+type ProvinceProps = {
province: Province;
provinceSlug: string;
};
-export default function ProvinceDatabase(props: ProvinceDatabaseProps) {
+export default function ProvincePage(props: ProvinceProps) {
const { province, provinceSlug } = props;
+ const [filteredContacts, handleSubmitKeywords] = useSearch(
+ props.province.data,
+ [
+ "kebutuhan",
+ "penyedia",
+ "lokasi",
+ "alamat",
+ "keterangan",
+ "kontak",
+ "tautan",
+ "tambahan_informasi",
+ "bentuk_verifikasi",
+ ]
+ );
if (province) {
return (
Database for {province.name}
-
+
+
);
} else {
@@ -39,7 +60,7 @@ export const getStaticPaths: GetStaticPaths = () => {
export const getStaticProps: GetStaticProps = ({ params = {} }) => {
const { provinceSlug } = params;
const index = getTheLastSegmentFromKebabCase(provinceSlug as string);
- const province = index ? database[index as unknown as number] : null;
+ const province = index ? provinces[index as unknown as number] : null;
return {
props: {
diff --git a/pages/provinces/index.tsx b/pages/provinces/index.tsx
new file mode 100644
index 000000000..2eb59ad14
--- /dev/null
+++ b/pages/provinces/index.tsx
@@ -0,0 +1,41 @@
+import { GetStaticProps } from "next";
+import provinces from "../../lib/provinces";
+import { getInitial, getSlug } from "../../lib/string-utils";
+import { SearchForm } from "../../components/search-form";
+import { ProvinceList, ProvinceListItem } from "../../components/province-list";
+import { useSearch } from "../../lib/hooks/use-search";
+
+type ProvincesPageProps = {
+ provincesList: ProvinceListItem[];
+};
+
+export default function ProvincesPage(props: ProvincesPageProps) {
+ const [filteredProvinces, handleSubmitKeywords] = useSearch(
+ props.provincesList,
+ ["name"]
+ );
+ return (
+
+
+ Daftar Provinsi
+
+
+
+
+ );
+}
+
+export const getStaticProps: GetStaticProps = () => {
+ const provincesList = provinces.map(({ name, data }, index) => ({
+ initials: getInitial(name),
+ name,
+ slug: getSlug(name, index),
+ count: data.length,
+ }));
+ provincesList.shift();
+ return {
+ props: {
+ provincesList,
+ },
+ };
+};