Skip to content

Commit

Permalink
feat: update Report type
Browse files Browse the repository at this point in the history
  • Loading branch information
baumstern committed Jan 26, 2024
1 parent f4abd31 commit 0c92120
Show file tree
Hide file tree
Showing 16 changed files with 673 additions and 571 deletions.
35 changes: 35 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Tests

on:
push:
branches:
- main
pull_request:

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

jobs:
test:
runs-on: ubuntu-22.04

steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v2
with:
version: 8

- name: Use Node.js 20
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'

- run: pnpm install

- run: pnpm build

- name: Test server functionality
run: pnpm exec vitest
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,27 @@ VoiceDeck is a platform that allows users to contribute retroactive funding for
We recommend [direnv](https://direnv.net/) for managing your environment variables


## Server Design

### Endpoint Details

`/impact-reports`
- **Returns**: An array of `Report` objects.
- **Purpose**: To provide impact reports to the UI.
- **Implementation Details**: Uses `fetchReports()` from `server/impactReportHelpers.ts`.

### Server Functions

Located in `app/server/impactReportHelpers.ts`:

- `fetchReports`: Function to retrieve reports, including interaction with Hypercerts.

### Data Models

- **Impact Report**: The report or stories that have been published previously and verified to actually produce an impact.
- **Hypercert**: A token representing a claim of impactful work, which is fractionable and transferable, conforming to the ERC-1155 standard for semi-fungible tokens.
- **Hypercert Metadata**: A set of data associated with a Hypercert, detailing the scope of work, contributors, impact, and rights, stored on IPFS.

### Separation of Concerns

The `/impact-reports` endpoint is responsible for serving impact reports. The implementation details of how the server retrieves data from Hypercert are abstracted away and managed within the `app/server/impactReportHelpers.ts` file.
9 changes: 0 additions & 9 deletions app/model/report.ts

This file was deleted.

54 changes: 26 additions & 28 deletions app/routes/_index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,4 @@
import type { MetaFunction } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";

import { Report } from "../model/report";
import { ReportService } from "../server/bootstrap.server";

export interface IReportLoader {
reports: Report[];
}

export const loader = async (): Promise<IReportLoader> => {
const reportService = await ReportService.getInstance();
return { reports: reportService.getReports() };
};

export const meta: MetaFunction = () => {
return [
Expand All @@ -21,23 +8,34 @@ export const meta: MetaFunction = () => {
};

export default function Index() {
const { reports } = useLoaderData<typeof loader>();
return (
<div>
<h1 className="text-7xl">Impact Report</h1>
<div className="text-xl">
{reports.map((report) => {
return (
<div key={report.name}>
-----
<br />
name: {report.name}
<br />
description: {report.description}
</div>
);
})}
</div>
<h1 className="text-7xl">Welcome to Remix</h1>
<ul>
<li>
<a
target="_blank"
href="https://remix.run/tutorials/blog"
rel="noreferrer"
>
15m Quickstart Blog Tutorial
</a>
</li>
<li>
<a
target="_blank"
href="https://remix.run/tutorials/jokes"
rel="noreferrer"
>
Deep Dive Jokes App Tutorial
</a>
</li>
<li>
<a target="_blank" href="https://remix.run/docs" rel="noreferrer">
Remix Docs
</a>
</li>
</ul>
</div>
);
}
103 changes: 0 additions & 103 deletions app/routes/hypercert-reports.server..tsx

This file was deleted.

37 changes: 37 additions & 0 deletions app/routes/impact-reports.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { fetchReports } from "~/server/impactReportHelpers";

export const loader = async () => {
const ownerAddress = process.env.HC_OWNER_ADDRESS;
try {
if (!ownerAddress) {
throw new Error("Owner address environment variable is not set");
}
const reports = await fetchReports(ownerAddress);
return new Response(JSON.stringify(reports), {
status: 200,
statusText: "OK",
});
} catch (error) {
console.error(`Failed to load impact reports: ${error}`);
return new Response(
JSON.stringify({ error: "Failed to load impact reports" }),
{
status: 500,
statusText: "Internal Server Error",
},
);
}
};

// or you can use loader like this and import it in the route file:
// export const loader = async (): Promise<IReportLoader> => {
// const ownerAddress = process.env.HC_OWNER_ADDRESS;
// return { reports: await fetchReports(ownerAddress) };
// };
//
//
// and then retrive the data like this in `Index()` function:
// export default function Index() {
// const { reports } = useLoaderData<typeof loader>();
// ...
// }
58 changes: 0 additions & 58 deletions app/server/bootstrap.server.ts

This file was deleted.

32 changes: 32 additions & 0 deletions app/server/impactReportHelpers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { it } from "node:test";
import { afterAll, expect, expectTypeOf, test, vi } from "vitest";
import { fetchReports } from "~/server/impactReportHelpers";
import { Report } from "~/types";

test("fetch reports", async () => {
// address used to mint test hypercerts in Sepolia testnet
const ownerAddress = "0x42fbf4d890b4efa0fb0b56a9cc2c5eb0e07c1536";
const consoleMock = vi.spyOn(console, "log");

afterAll(() => {
consoleMock.mockReset();
});

it("should fetch reports", async () => {
const result = await fetchReports(ownerAddress);

expectTypeOf(result).toEqualTypeOf<Report[]>();
expect(result.length).toBeGreaterThan(0);
expect(consoleMock).toHaveBeenCalledWith("Fetching reports from remote");
});

it("should not fetch reports if already cached", async () => {
const result = await fetchReports(ownerAddress);

expectTypeOf(result).toEqualTypeOf<Report[]>();
expect(result.length).toBeGreaterThan(0);
expect(consoleMock).toHaveBeenCalledWith(
"Reports already exist, no need to fetch from remote",
);
});
});
Loading

0 comments on commit 0c92120

Please sign in to comment.