Skip to content

Commit

Permalink
Add off chain registartion listing
Browse files Browse the repository at this point in the history
  • Loading branch information
Corantin committed May 22, 2024
1 parent d4a029c commit 18a1908
Show file tree
Hide file tree
Showing 42 changed files with 850 additions and 437 deletions.
21 changes: 15 additions & 6 deletions packages/nextjs/clients/base.client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class HttpClient {
const res = await fetch(url, {
headers: [["authorization", this.authorizationToken ?? ""]],
});
const error = this.handleError(url, res);
const error = await this.handleError(url, res);
if (error) return { status: res.status, error, value: undefined, ok: false };

return { status: res.status, value: (await res.json()) as TRes, ok: true };
Expand All @@ -37,7 +37,7 @@ export class HttpClient {
body: body,
headers: [["authorization", this.authorizationToken ?? ""], ...(headers ?? [])],
});
const error = this.handleError(url, res);
const error = await this.handleError(url, res);
if (error) return { status: res.status, error, value: undefined, ok: false };

return { status: res.status, value: (await res.text()) as TRes, ok: true };
Expand All @@ -50,7 +50,7 @@ export class HttpClient {
body: body,
headers: [["authorization", this.authorizationToken ?? ""]],
});
const error = this.handleError(url, res);
const error = await this.handleError(url, res);
if (error) return { status: res.status, error, value: undefined, ok: false };

return { status: res.status, value: (await res.text()) as TRes, ok: true };
Expand All @@ -62,13 +62,13 @@ export class HttpClient {
method: "DELETE",
headers: [["authorization", this.authorizationToken ?? ""]],
});
const error = this.handleError(url, res);
const error = await this.handleError(url, res);
if (error) return { status: res.status, error, value: undefined, ok: false };

return { status: res.status, ok: true };
}

private handleError(url: string, res: Response) {
private async handleError(url: string, res: Response) {
if (res.status === 401) {
const message = "Unauthorized";
logger.error({ message, url });
Expand All @@ -81,6 +81,12 @@ export class HttpClient {
return message;
}

if (res.status === 453) {
const message = await res.text();
logger.error({ message, url });
return message;
}

if (res.status === 404) {
const message = "Not Found";
logger.error({ message, url });
Expand All @@ -103,10 +109,13 @@ export class HttpClient {
}

private appendQueryParams(url: string, params: any = {}) {
if (!params) return url;
const [path, query] = url.split("?");
const searchParams = new URLSearchParams(query);
Object.keys(params).forEach(key => {
searchParams.append(key, params[key].toString());
if (params[key] != null) {
searchParams.append(key, params[key].toString());
}
});
return `${path}?${searchParams.toString()}`;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import useHttpClient, { HttpClient } from "./base.client";
import { ExplorerPageSize } from "~~/constants";
import { defaultPropertyFilter } from "~~/contexts/property-filter.context";
import { DeedInfoModel } from "~~/models/deed-info.model";
import { PropertiesFilterModel } from "~~/models/properties-filter.model";
import logger from "~~/services/logger.service";

// LINK ../pages/api/deed.api.ts
Expand All @@ -8,8 +11,9 @@ export class DeedClient extends HttpClient {
async saveDeed(deed: DeedInfoModel) {
const result = await this.post<string>("/api/deeds", undefined, JSON.stringify(deed));
if (!result.ok) {
logger.error({ message: "Error creating deed", status: result.status });
logger.error({ message: "Error saving deed", status: result.status });
}

return result;
}

Expand All @@ -20,6 +24,19 @@ export class DeedClient extends HttpClient {

return result;
}

async searchDeeds(
filter?: PropertiesFilterModel,
currentPage: number = 0,
pageSize: number = ExplorerPageSize,
) {
const result = await this.get<DeedInfoModel[]>(`/api/deeds`, {
...(filter ?? defaultPropertyFilter),
currentPage,
pageSize,
});
return result;
}
}

const useDeedClient = () => useHttpClient(new DeedClient());
Expand Down
9 changes: 6 additions & 3 deletions packages/nextjs/clients/validations.client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ import logger from "~~/services/logger.service";

export class ValidationClient extends HttpClient {
public async getValidation(
deedId: string,
registrationId: string,
key: string,
): Promise<FileValidationModel | undefined> {
const result = await this.get<FileValidationModel>("/api/validations", { key, deedId });
const result = await this.get<FileValidationModel>("/api/validations", {
key,
registrationId,
});
if (!result.ok) {
logger.error({
error: result.error,
message: `Failed to retrieve validation with deedId: ${deedId} and key: ${key}`,
message: `Failed to retrieve validation with registrationId: ${registrationId} and key: ${key}`,
});
return undefined;
}
Expand Down
10 changes: 5 additions & 5 deletions packages/nextjs/components/FileValidation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ const FileValidation = ({

useEffect(() => {
(async () => {
if (!deedData.registrationId) return;
const result = await validationClient.getValidation(deedData.registrationId, key);
if (!deedData.id) return;
const result = await validationClient.getValidation(deedData.id, key);
if (!result) {
notification.error(`Error retrieving validation with key: ${key}`);
} else {
Expand Down Expand Up @@ -149,7 +149,7 @@ const FileValidation = ({
const handleStateChanged = (ev: any) => {
const newState = ev.target.value as FileValidationState;
setFileValidationState(newState);
onStateChanged?.({ key: key, state: newState, registrationId: deedData.registrationId! });
onStateChanged?.({ key: key, state: newState, registrationId: deedData.id! });
setIsBadgeEdit(false);
};

Expand Down Expand Up @@ -187,7 +187,7 @@ const FileValidation = ({
}}
>
{loading ? (
<div className="h-2 w-16 bg-slate-300 rounded"></div>
<div className="h-2 w-16 bg-slate-300 rounded" />
) : (
fileValidationState ?? "Not started"
)}
Expand Down Expand Up @@ -243,7 +243,7 @@ const FileValidation = ({
isRestricted={field.restricted}
// @ts-ignore
onChange={newFile => handleFileUpload(newFile as FileModel, field)}
></FileUploaderInput>
/>
</div>
)}
</div>
Expand Down
7 changes: 2 additions & 5 deletions packages/nextjs/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,8 @@ export const Header = () => {
viewBox="0 0 121 34"
fill="none"
xmlns="http://www.w3.org/2000/svg"
onClick={ev => {
if (ev.altKey && ev.ctrlKey) {
router.push("/admin");
ev.stopPropagation();
}
onDoubleClick={() => {
router.push("/admin");
}}
>
<path
Expand Down
5 changes: 4 additions & 1 deletion packages/nextjs/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { BackToTop } from "~~/components/BackToTop";
import ErrorBoundary from "~~/components/ErrorBoundary";
import { Footer } from "~~/components/Footer";
import { Header } from "~~/components/Header";
import { PropertiesFilterProvider } from "~~/contexts/property-filter.context";

const Layout = ({ pageProps, Component }: AppProps) => {
// const connectBtnRef = useRef<HTMLInputElement>(null);
Expand All @@ -32,7 +33,9 @@ const Layout = ({ pageProps, Component }: AppProps) => {
<Header />
<main className="relative flex flex-col flex-1">
<ErrorBoundary>
<Component {...pageProps} />
<PropertiesFilterProvider>
<Component {...pageProps} />
</PropertiesFilterProvider>
</ErrorBoundary>
</main>
<Footer />
Expand Down
2 changes: 1 addition & 1 deletion packages/nextjs/components/OwnerInformation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const OwnerInformation = ({ value, onChange, readOnly }: Props) => {
onChange={handleChange}
value={value?.ownerType}
readOnly={readOnly}
></RadioBoxesInput>
/>
<div className="grid grid-cols-1 sm:grid-cols-3 gap-6 sm:gap-3 justify-start w-full">
{value?.ownerType === "legal" && (
<TextInput
Expand Down
2 changes: 1 addition & 1 deletion packages/nextjs/components/PropertyCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { PropertyModel } from "~~/models/property.model";

interface Props {
property: PropertyModel;
small: boolean;
small?: boolean;
}

const PropertyCard = ({ property, small = false }: Props) => {
Expand Down
65 changes: 24 additions & 41 deletions packages/nextjs/components/PropertyFilters.tsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,33 @@
import React, { useEffect, useState } from "react";
import { useSearchParams } from "next/navigation";
import React, { useState } from "react";
import ExplorerLinks from "./ExplorerLinks";
import PropertyCard from "./PropertyCard";
import TextInput from "./inputs/TextInput";
import Map from "./map";
import { debounce } from "lodash-es";
import { AddressInput } from "./scaffold-eth";
import { useLocalStorage } from "usehooks-ts";
import { MapIcon } from "@heroicons/react/24/outline";
import { MapIcon as MapIconSolid } from "@heroicons/react/24/solid";
import { AdjustmentsHorizontalIcon } from "@heroicons/react/24/solid";
import { PropertyTypeOptions } from "~~/constants";
import { usePropertiesFilter } from "~~/contexts/property-filter.context";
import useIsValidator from "~~/hooks/contracts/access-manager/useIsValidator.hook";
import { useKeyboardShortcut } from "~~/hooks/useKeyboardShortcut";
import { PropertyType } from "~~/models/deed-info.model";
import { MarkerModel } from "~~/models/marker.model";
import { PropertiesFilterModel } from "~~/models/properties-filter.model";
import { PropertyModel } from "~~/models/property.model";

interface Props {
properties: PropertyModel[];
onFilter: (filter?: PropertiesFilterModel) => void;
}

const PropertyFilters = ({ properties, onFilter }: Props) => {
const searchParams = useSearchParams();
const PropertyFilters = ({ properties }: Props) => {
const isValidator = useIsValidator();
const [mapOpened, setMapOpened] = useLocalStorage("PropertyFilter.MapOpened", false);
const [isMoreFilters, setIsMoreFilters] = useState(false);
const [filter, setFilter] = useState<PropertiesFilterModel>({
listingType: searchParams.get("type") as PropertiesFilterModel["listingType"],
});
// Define the method directly in your class
const [search, setSearch] = useState("");

const searchDebounce = debounce((search: string) => {
applyFilter({ ...filter, search });
}, 500);

useEffect(() => {
searchDebounce(search);
}, [search]);

const applyFilter = (partialFilter: Partial<PropertiesFilterModel>) => {
const newFilter = { ...filter, ...partialFilter };
setFilter(newFilter);
onFilter(newFilter);
};
const { filter, applyFilter } = usePropertiesFilter();

useKeyboardShortcut(["Enter"], () => {
onFilter(filter);
applyFilter(filter);
});

return (
Expand All @@ -56,10 +36,11 @@ const PropertyFilters = ({ properties, onFilter }: Props) => {
<div className="filters">
<div className="flex flex-row flex-wrap sm:flex-nowrap justify-start items-center gap-2 md:gap-4 w-full">
<input
name="Search"
className="input input-md sm:input-lg border-white border-opacity-10 bg-base-300 sm:text-[16px] py-2 sm:py-0 w-full sm:flex-grow"
placeholder="Search by City, State, or Zip code"
value={search}
onChange={e => setSearch(e.target.value)}
value={filter.search}
onChange={ev => applyFilter({ search: ev.target.value })}
/>
<button
className="btn btn-md sm:btn-lg border-white border-opacity-10 bg-base-300 sm:text-[16px] font-normal capitalize items-center gap-2 h-auto"
Expand Down Expand Up @@ -114,34 +95,36 @@ const PropertyFilters = ({ properties, onFilter }: Props) => {
<select
className="select select-md sm:select-lg border-white border-opacity-10 sm:text-[16px]"
value={filter.validated}
onChange={ev =>
onChange={ev => {
applyFilter({
validated: ev.currentTarget.value as PropertiesFilterModel["validated"],
})
}
});
}}
>
<option value="true">Verified</option>
<option value="false">Not verified</option>
<option value="all">All</option>
</select>
)}
<input
type="text"
<TextInput
name="PropertySize"
placeholder="Property Size"
className="input input-md sm:input-lg border-white border-opacity-10 sm:text-[16px]"
value={filter.propertySize}
onChange={ev =>
applyFilter({
propertySize: ev.target.value,
propertySize: ev.value,
})
}
large
/>
<input
type="text"
<AddressInput
placeholder="Owner wallet"
className="input input-md sm:input-lg border-white border-opacity-10 sm:text-[16px]"
onChange={ev =>
name="OwnerWallet"
value={filter.ownerWallet ?? ""}
large
onChange={address =>
applyFilter({
ownerWallet: ev.target.value,
ownerWallet: address,
})
}
/>
Expand Down
Loading

0 comments on commit 18a1908

Please sign in to comment.