Skip to content

Commit

Permalink
Migrate to Remix
Browse files Browse the repository at this point in the history
  • Loading branch information
sembrestels committed Nov 3, 2024
1 parent 559f446 commit c836ee5
Show file tree
Hide file tree
Showing 24 changed files with 310 additions and 135 deletions.
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ coverage.json
.vercel

# Build Outputs
.next/
out/
build
dist

Expand Down
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,25 @@ bun run dev
The development server will be available at http://localhost:3000/.

The smart contracts are in the `contracts` directory, and the frontend is in the `apps` directory.

## How to deploy

### Build Settings

- **Docker Image:**
`node:lts`

- **Repository:**
[https://github.com/BlossomLabs/councilhaus](https://github.com/BlossomLabs/councilhaus)

- **Build Command:**
```bash
npm install -g bun && HUSKY=0 bun i && bun run --cwd apps/web/ build
```

- **Publish Directory:**
`apps/web/build`

### Environment Variables

- Use `VITE_WALLETCONNECT_PROJECT_ID` for your wallet connect project ID.
5 changes: 0 additions & 5 deletions apps/web/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@
# testing
/coverage

# next.js
/.next/
/out/

# production
/build

Expand All @@ -33,4 +29,3 @@ yarn-error.log*

# typescript
*.tsbuildinfo
next-env.d.ts
12 changes: 0 additions & 12 deletions apps/web/next.config.mjs

This file was deleted.

17 changes: 11 additions & 6 deletions apps/web/package.json
Original file line number Diff line number Diff line change
@@ -1,32 +1,37 @@
{
"name": "web",
"version": "1.0.0",
"version": "1.1.0",
"private": true,
"sideEffects": false,
"type": "module",
"scripts": {
"dev": "next dev --port 3000",
"build": "next build",
"start": "next start"
"build": "remix vite:build",
"dev": "remix vite:dev -l info"
},
"dependencies": {
"@rainbow-me/rainbowkit": "^2.1.5",
"@remix-run/node": "^2.12.1",
"@remix-run/react": "^2.12.1",
"@repo/ui": "*",
"@tanstack/react-query": "^5.55.4",
"ethereum-blockies-base64": "^1.0.2",
"graphql-request": "^7.1.0",
"next": "^14.2.8",
"react": "^18",
"react-dom": "^18",
"viem": "2.x",
"wagmi": "^2.12.8"
},
"devDependencies": {
"@remix-run/dev": "^2.12.1",
"@repo/typescript-config": "*",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"autoprefixer": "^10",
"postcss": "^8",
"tailwindcss": "^3.4.10",
"typescript": "^5"
"typescript": "^5",
"vite": "^5.1.0",
"vite-tsconfig-paths": "^5.0.0"
}
}
18 changes: 18 additions & 0 deletions apps/web/src/app/entry.client.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* By default, Remix will handle hydrating your app on the client for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/file-conventions/entry.client
*/

import { RemixBrowser } from "@remix-run/react";
import { StrictMode, startTransition } from "react";
import { hydrateRoot } from "react-dom/client";

startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<RemixBrowser />
</StrictMode>,
);
});
46 changes: 0 additions & 46 deletions apps/web/src/app/layout.tsx

This file was deleted.

74 changes: 74 additions & 0 deletions apps/web/src/app/root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import type { MetaFunction } from "@remix-run/node";
import {
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from "@remix-run/react";

import { ToastProvider } from "@repo/ui/components/ui/toast";
import { Toaster } from "@repo/ui/components/ui/toaster";
import { TooltipProvider } from "@repo/ui/components/ui/tooltip";
import { Layout } from "../components/Layout";
import { WalletProvider } from "../context/WalletProvider";

import {
SITE_DESCRIPTION,
SITE_EMOJI,
SITE_NAME,
SITE_URL,
SOCIAL_TWITTER,
} from "../../../../constants";

import "@repo/ui/globals.css";
import "@rainbow-me/rainbowkit/styles.css";

export const meta: MetaFunction = () => [
{
charset: "utf-8",
title: SITE_NAME,
viewport: "width=device-width,initial-scale=1",
},
{ name: "description", content: SITE_DESCRIPTION },
{ name: "image", content: SITE_EMOJI },
{ name: "og:image", content: "/opengraph-image" },
{ name: "og:title", content: SITE_NAME },
{ name: "og:description", content: SITE_DESCRIPTION },
{ name: "og:url", content: SITE_URL },
{ name: "og:type", content: "website" },
{ name: "og:site_name", content: SITE_NAME },
{ name: "og:locale", content: "en_US" },
{ name: "twitter:card", content: "summary_large_image" },
{ name: "twitter:image", content: "/opengraph-image" },
{ name: "twitter:title", content: SITE_NAME },
{ name: "twitter:description", content: SITE_DESCRIPTION },
{ name: "twitter:site", content: SOCIAL_TWITTER },
{ name: "twitter:creator", content: SOCIAL_TWITTER },
];

export default function App() {
return (
<html lang="en">
<head>
<Meta />
<Links />
</head>
<body>
<WalletProvider>
<ToastProvider>
<TooltipProvider>
<Layout>
<Outlet />
</Layout>
</TooltipProvider>
<Toaster />
</ToastProvider>
</WalletProvider>
<ScrollRestoration />
<Scripts />
</body>
</html>
);
}
13 changes: 13 additions & 0 deletions apps/web/src/app/routes/_index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { DEFAULT_COUNCIL_ADDRESS, NETWORK } from "../../../../../constants";

export default function IndexPage() {
const navigate = useNavigate();

useEffect(() => {
navigate(`/c/${NETWORK}/${DEFAULT_COUNCIL_ADDRESS}`);
}, [navigate]);

return null;
}
Original file line number Diff line number Diff line change
@@ -1,37 +1,53 @@
"use client";

import { useParams } from "@remix-run/react";
import { Badge } from "@repo/ui/components/ui/badge";
import { Label } from "@repo/ui/components/ui/label";
import { Skeleton } from "@repo/ui/components/ui/skeleton";
import { cn } from "@repo/ui/lib/utils";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { getAddress } from "viem";
import { useAccount, useChains } from "wagmi";
import { DEFAULT_COUNCIL_ADDRESS, NETWORK } from "../../../../constants";
import { CouncilImage } from "../components/CouncilImage";
import { CouncilName } from "../components/CouncilName";
import VotingCard from "../components/VotingCard";
import { useAllocation } from "../hooks/useAllocation";
import { useCouncil } from "../hooks/useCouncil";
import { NETWORK } from "../../../../../constants";
import { CouncilImage } from "../../components/CouncilImage";
import { CouncilName } from "../../components/CouncilName";
import VotingCard from "../../components/VotingCard";
import { useAllocation } from "../../hooks/useAllocation";
import { useCouncil } from "../../hooks/useCouncil";

export default function Page() {
const router = useRouter();
const [council, setCouncil] = useState<`0x${string}` | undefined>(undefined);
export default function CouncilPage() {
const { chain, council } = useParams();
const navigate = useNavigate();
const normalizedAddress = council ? getAddress(council) : null;

useEffect(() => {
// Ensure the code runs only on the client side
if (!window.location.hash) {
router.push(`#${DEFAULT_COUNCIL_ADDRESS}`);
// Redirect if the chain is unsupported
if (chain !== NETWORK) {
navigate("/404");
return;
}
// Set the council value once the hash is present
const address = getAddress(
window.location.hash?.slice(1) || DEFAULT_COUNCIL_ADDRESS,
);
setCouncil(address);
}, [router]);

// Redirect if council address is invalid
if (!normalizedAddress) {
navigate("/404");
return;
}

// Redirect if the normalized address doesn't match the URL
if (normalizedAddress !== council) {
navigate(`/c/${chain}/${normalizedAddress}`, { replace: true });
}
}, [chain, council, normalizedAddress, navigate]);

if (!normalizedAddress) {
return null;
}

return <CouncilPageContent council={normalizedAddress} />;
}

function CouncilPageContent({ council }: { council: `0x${string}` }) {
// Fetch data when the council is available
const { address } = useAccount();
const {
Expand All @@ -52,16 +68,17 @@ export default function Page() {

return (
<main>
<Link
<a
href={`https://explorer.superfluid.finance/${NETWORK}-mainnet/accounts/${council}?tab=pools`}
target="_blank"
rel="noreferrer"
>
<CouncilImage image={councilImage} />
<CouncilName
name={councilName}
className="min-h-12 text-4xl font-semibold tracking-wider text-accent mb-4 text-center"
/>
</Link>
</a>
<div className="flex flex-col gap-4 mt-4 mb-12 text-justify">
{totalVotingPower ? (
!address ? (
Expand Down Expand Up @@ -129,14 +146,22 @@ function ContractLinks({
<div className={cn("flex flex-row gap-1 mb-4 items-center", className)}>
<Label className="pr-2">Contracts: </Label>
<Badge variant="outline">
<Link href={`${explorer}/address/${council}`} target="_blank">
<a
href={`${explorer}/address/${council}`}
target="_blank"
rel="noreferrer"
>
Council
</Link>
</a>
</Badge>
<Badge variant="outline">
<Link href={`${explorer}/address/${pool}`} target="_blank">
<a
href={`${explorer}/address/${pool}`}
target="_blank"
rel="noreferrer"
>
Pool
</Link>
</a>
</Badge>
</div>
);
Expand Down
Loading

0 comments on commit c836ee5

Please sign in to comment.