Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ NEXT_PUBLIC_HATHOR_NODE_URL_TESTNET=https://node1.india-testnet.hathor.network/v
NEXT_PUBLIC_HATHOR_NODE_URL_MAINNET=https://node1.mainnet.hathor.network/v1a

# Contract IDs
# Add your deployed contract IDs as a JSON array
# Add deployed contract IDs as JSON arrays per network
# Example: ["0abc123...", "def456..."]
NEXT_PUBLIC_CONTRACT_IDS=[]
NEXT_PUBLIC_CONTRACT_IDS_TESTNET=[]
NEXT_PUBLIC_CONTRACT_IDS_MAINNET=[]
3 changes: 0 additions & 3 deletions .eslintrc.json

This file was deleted.

69 changes: 69 additions & 0 deletions .github/workflows/pr-preview-cleanup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: PR Preview Cleanup

on:
pull_request:
types: [closed]
branches:
- master
- main

permissions:
contents: write
issues: write
pull-requests: write

jobs:
cleanup-preview:
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
steps:
- name: Remove PR preview directory from gh-pages
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
REPO_URL="https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"

if ! git ls-remote --exit-code --heads "$REPO_URL" gh-pages >/dev/null; then
echo "No gh-pages branch found, nothing to clean up."
exit 0
fi

git clone --single-branch --branch gh-pages --depth 1 "$REPO_URL" gh-pages-out

PR_DIR="gh-pages-out/pr-${PR_NUMBER}"
if [ ! -d "$PR_DIR" ]; then
echo "No preview directory found for PR #${PR_NUMBER}, nothing to clean up."
exit 0
fi

cd gh-pages-out
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git rm -rf "pr-${PR_NUMBER}"
git commit -m "chore: remove preview for PR #${PR_NUMBER}"
git push origin gh-pages

- name: Update PR comment
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
export GH_TOKEN="$GITHUB_TOKEN"
MARKER="<!-- pr-preview-url -->"

COMMENT_ID=$(gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments?per_page=100" \
--jq ".[] | select(.body | startswith(\"${MARKER}\")) | .id" | head -1)

if [ -z "$COMMENT_ID" ]; then
echo "No preview comment found, nothing to update."
exit 0
fi

BODY="${MARKER}
## Preview deployment

Preview has been removed as this PR is now closed."

gh api -X PATCH "repos/${GITHUB_REPOSITORY}/issues/comments/${COMMENT_ID}" \
--input - <<< "$(jq -n --arg body "$BODY" '{"body": $body}')"
115 changes: 115 additions & 0 deletions .github/workflows/pr-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
name: PR Preview

on:
pull_request:
types: [opened, synchronize, reopened]
branches:
- master
- main

concurrency:
group: pr-preview-${{ github.event.pull_request.number }}
cancel-in-progress: true

permissions:
contents: write
issues: write
pull-requests: write

jobs:
deploy-preview:
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
steps:
- name: Checkout repository
# https://github.com/actions/checkout/releases/tag/v4.2.2
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683

- name: Set up Node.js 22.x
# https://github.com/actions/setup-node/releases/tag/v6.1.0
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f
with:
node-version: 22.x
cache: npm

- name: Install dependencies
run: npm ci

- name: Build static preview
env:
NEXT_OUTPUT_MODE: export
NEXT_PUBLIC_BASE_PATH: /${{ github.event.repository.name }}/pr-${{ github.event.pull_request.number }}
NEXT_PUBLIC_DEFAULT_NETWORK: testnet
NEXT_PUBLIC_HATHOR_NODE_URL_TESTNET: https://node1.india.testnet.hathor.network/v1a
NEXT_PUBLIC_HATHOR_NODE_URL_MAINNET: https://node1.mainnet.hathor.network/v1a
NEXT_PUBLIC_CONTRACT_IDS_TESTNET: '["00000000361ec0406d90a5bb4c6c7330af5792178b86cfc353afd4e50a62b741"]'
NEXT_PUBLIC_CONTRACT_IDS_MAINNET: '["000003e0baf17eee5a25aa0ccf36eb331a05818c87bc1c316f54485aa974c485"]'
NEXT_PUBLIC_USE_MOCK_WALLET: 'false'
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID: 8264fff563181da658ce64ee80e80458
run: npm run build

- name: Deploy to gh-pages branch
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
REPO_URL="https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"

if git clone --single-branch --branch gh-pages --depth 1 "$REPO_URL" gh-pages-out 2>/dev/null; then
echo "Cloned existing gh-pages branch"
else
echo "Creating new gh-pages branch"
mkdir gh-pages-out
cd gh-pages-out
git init
git remote add origin "$REPO_URL"
git checkout --orphan gh-pages
cd ..
fi

touch gh-pages-out/.nojekyll
rm -rf "gh-pages-out/pr-${PR_NUMBER}"
mkdir -p "gh-pages-out/pr-${PR_NUMBER}"
cp -r out/. "gh-pages-out/pr-${PR_NUMBER}/"

cd gh-pages-out
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add .nojekyll "pr-${PR_NUMBER}/"
git diff --cached --quiet || git commit -m "deploy: preview for PR #${PR_NUMBER} @ ${HEAD_SHA}"
git push origin gh-pages

- name: Post or update PR comment
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
export GH_TOKEN="$GITHUB_TOKEN"
MARKER="<!-- pr-preview-url -->"
REPO_NAME="${GITHUB_REPOSITORY#*/}"
PREVIEW_URL="https://${GITHUB_REPOSITORY_OWNER}.github.io/${REPO_NAME}/pr-${PR_NUMBER}/"

BODY="${MARKER}
## Preview deployment

| | |
|---|---|
| **URL** | ${PREVIEW_URL} |
| **Commit** | \`${HEAD_SHA}\` |

> This preview is automatically updated on every push and removed when the PR is closed."

COMMENT_ID=$(gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments?per_page=100" \
--jq ".[] | select(.body | startswith(\"${MARKER}\")) | .id" | head -1)

PAYLOAD=$(jq -n --arg body "$BODY" '{"body": $body}')

if [ -n "$COMMENT_ID" ]; then
gh api -X PATCH "repos/${GITHUB_REPOSITORY}/issues/comments/${COMMENT_ID}" \
--input - <<< "$PAYLOAD"
else
gh api -X POST "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" \
--input - <<< "$PAYLOAD"
fi
7 changes: 4 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Frontend Dockerfile - Multi-stage build for Next.js SSR
FROM node:18-alpine AS builder
FROM node:22-alpine AS builder

# Set working directory
WORKDIR /app
Expand All @@ -22,7 +22,8 @@ ENV NEXT_PUBLIC_USE_MOCK_WALLET=false
ENV NEXT_PUBLIC_DEFAULT_NETWORK=testnet
ENV NEXT_PUBLIC_HATHOR_NODE_URL_TESTNET=https://node1.india.testnet.hathor.network/v1a
ENV NEXT_PUBLIC_HATHOR_NODE_URL_MAINNET=https://node1.mainnet.hathor.network/v1a
ENV NEXT_PUBLIC_CONTRACT_IDS='["0000000079862340c1f7822b81f58668e2a62c5f1b69d8d2e3b8fdf1855196c1"]'
ENV NEXT_PUBLIC_CONTRACT_IDS_TESTNET='["00000000361ec0406d90a5bb4c6c7330af5792178b86cfc353afd4e50a62b741"]'
ENV NEXT_PUBLIC_CONTRACT_IDS_MAINNET='["000003e0baf17eee5a25aa0ccf36eb331a05818c87bc1c316f54485aa974c485"]'
ENV NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=8264fff563181da658ce64ee80e80458

# Set environment for production build
Expand All @@ -32,7 +33,7 @@ ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build

# Production stage
FROM node:18-alpine AS runner
FROM node:22-alpine AS runner

# Install curl for health checks and other utilities
RUN apk add --no-cache curl
Expand Down
5 changes: 3 additions & 2 deletions INTEGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,8 @@ NEXT_PUBLIC_USE_MOCK_WALLET=true
NEXT_PUBLIC_DEFAULT_NETWORK=testnet
NEXT_PUBLIC_HATHOR_NODE_URL_TESTNET=https://node1.india.testnet.hathor.network/v1a
NEXT_PUBLIC_HATHOR_NODE_URL_MAINNET=https://node1.mainnet.hathor.network/v1a
NEXT_PUBLIC_CONTRACT_IDS=["contract_id"]
NEXT_PUBLIC_CONTRACT_IDS_TESTNET=["contract_id"]
NEXT_PUBLIC_CONTRACT_IDS_MAINNET=[]
```

## Testing
Expand All @@ -194,7 +195,7 @@ NEXT_PUBLIC_CONTRACT_IDS=["contract_id"]

### Immediate
1. Deploy contract to India Testnet
2. Update `NEXT_PUBLIC_CONTRACT_IDS` with real contract ID
2. Update `NEXT_PUBLIC_CONTRACT_IDS_TESTNET` with real contract ID
3. Test with real wallet
4. Verify all calculations match contract

Expand Down
5 changes: 3 additions & 2 deletions QUICKSTART.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ All actions are simulated and no real transactions occur.
1. **Update Environment**:
```env
NEXT_PUBLIC_USE_MOCK_WALLET=false
NEXT_PUBLIC_CONTRACT_IDS=["your_contract_id_here"]
NEXT_PUBLIC_CONTRACT_IDS_TESTNET=["your_contract_id_here"]
NEXT_PUBLIC_CONTRACT_IDS_MAINNET=[]
```

2. **Restart Server**:
Expand Down Expand Up @@ -89,7 +90,7 @@ The Contract Information panel shows:
- Check that you're on the correct network

### "Contract state not loaded"
- Verify `NEXT_PUBLIC_CONTRACT_IDS` is set correctly
- Verify `NEXT_PUBLIC_CONTRACT_IDS_TESTNET` or `NEXT_PUBLIC_CONTRACT_IDS_MAINNET` is set correctly for the selected network
- Check that the contract exists on the selected network
- Ensure node URL is accessible

Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ NEXT_PUBLIC_USE_MOCK_WALLET=true
NEXT_PUBLIC_DEFAULT_NETWORK=india-testnet
NEXT_PUBLIC_HATHOR_NODE_URL_TESTNET=https://node1.india-testnet.hathor.network/v1a
NEXT_PUBLIC_HATHOR_NODE_URL_MAINNET=https://node1.mainnet.hathor.network/v1a
NEXT_PUBLIC_CONTRACT_IDS=["contract_id_1","contract_id_2"]
NEXT_PUBLIC_CONTRACT_IDS_TESTNET=["contract_id_1","contract_id_2"]
NEXT_PUBLIC_CONTRACT_IDS_MAINNET=[]
```

## Setup Instructions
Expand Down Expand Up @@ -86,7 +87,7 @@ cp .env.local.example .env.local

Edit `.env.local` with your configuration:
- Set `NEXT_PUBLIC_USE_MOCK_WALLET=false` for production
- Add your contract IDs to `NEXT_PUBLIC_CONTRACT_IDS`
- Add your contract IDs to `NEXT_PUBLIC_CONTRACT_IDS_TESTNET` and/or `NEXT_PUBLIC_CONTRACT_IDS_MAINNET`
- Configure network URLs if using custom nodes

4. Run development server:
Expand Down
6 changes: 4 additions & 2 deletions STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,15 @@ NEXT_PUBLIC_USE_MOCK_WALLET=true
NEXT_PUBLIC_DEFAULT_NETWORK=india-testnet
NEXT_PUBLIC_HATHOR_NODE_URL_TESTNET=https://node1.india.testnet.hathor.network/v1a
NEXT_PUBLIC_HATHOR_NODE_URL_MAINNET=https://node1.mainnet.hathor.network/v1a
NEXT_PUBLIC_CONTRACT_IDS=[]
NEXT_PUBLIC_CONTRACT_IDS_TESTNET=[]
NEXT_PUBLIC_CONTRACT_IDS_MAINNET=[]
```

### For Production
```env
NEXT_PUBLIC_USE_MOCK_WALLET=false
NEXT_PUBLIC_CONTRACT_IDS=["your_deployed_contract_id"]
NEXT_PUBLIC_CONTRACT_IDS_TESTNET=[]
NEXT_PUBLIC_CONTRACT_IDS_MAINNET=["your_deployed_contract_id"]
```

## Testing Checklist
Expand Down
3 changes: 2 additions & 1 deletion app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import { HathorProvider } from '@/contexts/HathorContext';
import { WalletConnectProvider } from '@/contexts/WalletConnectContext';
import { MetaMaskProvider } from '@/contexts/MetaMaskContext';
import { UnifiedWalletProvider } from '@/contexts/UnifiedWalletContext';
import { publicAsset } from '@/lib/publicAsset';
import { ToastProvider, Toaster } from '@/lib/toast';
import './globals.css';

export const metadata: Metadata = {
title: 'Hathor Dice - Provably Fair Betting',
description: 'Decentralized dice game on Hathor Network',
icons: {
icon: '/images/icon.png',
icon: publicAsset('/images/icon.png'),
},
};

Expand Down
13 changes: 7 additions & 6 deletions components/GoddessSpinner.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import React, { useEffect, useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { publicAsset } from '@/lib/publicAsset';

interface GoddessSpinnerProps {
size?: number;
interval?: number;
}

const GODDESS_IMAGES = [
'/images/cartoon_anubis.png',
'/images/cartoon_pharaoh.png',
'/images/cartoon_scarab.png',
'/images/cartoon_eye_of_horus.png',
'/images/cartoon_pyramid.png',
'/images/cartoon_mummy.png',
publicAsset('/images/cartoon_anubis.png'),
publicAsset('/images/cartoon_pharaoh.png'),
publicAsset('/images/cartoon_scarab.png'),
publicAsset('/images/cartoon_eye_of_horus.png'),
publicAsset('/images/cartoon_pyramid.png'),
publicAsset('/images/cartoon_mummy.png'),
];

export function GoddessSpinner({ size = 64, interval = 800 }: GoddessSpinnerProps) {
Expand Down Expand Up @@ -48,7 +49,7 @@
exit={{ opacity: 0, scale: 0.5, rotate: 20 }}
transition={{ type: "spring", stiffness: 300, damping: 20 }}
>
<img

Check warning on line 52 in components/GoddessSpinner.tsx

View workflow job for this annotation

GitHub Actions / Lint

Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element
src={GODDESS_IMAGES[currentIndex]}
alt="Loading..."
loading="eager"
Expand Down
4 changes: 3 additions & 1 deletion components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { useState } from 'react';
import { useHathor } from '@/contexts/HathorContext';
import { publicAsset } from '@/lib/publicAsset';
import { formatAddress } from '@/lib/utils';
import { WalletConnectionModal } from './WalletConnectionModal';
import { NetworkSelector } from './NetworkSelector';
Expand All @@ -16,6 +17,7 @@
const { isConnected, address, disconnectWallet, network, switchNetwork } = useHathor();
const [showModal, setShowModal] = useState(false);
const [showDisconnectMenu, setShowDisconnectMenu] = useState(false);
const iconSrc = publicAsset('/images/icon.png');

const handleConnect = async () => {
setShowModal(true);
Expand All @@ -34,7 +36,7 @@
<header className="flex items-center justify-between p-6 border-b border-slate-700">
<div className="flex items-center gap-4">
<h1 className="text-2xl font-bold text-white">HATHOR DICE</h1>
<img src="/images/icon.png" alt="Hathor Dice" className="w-12 h-12" />
<img src={iconSrc} alt="Hathor Dice" className="w-12 h-12" />

Check warning on line 39 in components/Header.tsx

View workflow job for this annotation

GitHub Actions / Lint

Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element
</div>

<div className="flex items-center gap-2">
Expand Down
7 changes: 5 additions & 2 deletions components/IntroVideo.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';

import { useState, useRef, useEffect } from 'react';
import { publicAsset } from '@/lib/publicAsset';

interface IntroVideoProps {
onComplete: () => void;
Expand All @@ -10,6 +11,8 @@ export function IntroVideo({ onComplete }: IntroVideoProps) {
const videoRef = useRef<HTMLVideoElement>(null);
const [showPlayButton, setShowPlayButton] = useState(true);
const onCompleteRef = useRef(onComplete);
const videoSrc = publicAsset('/videos/intro.mp4');
const posterSrc = publicAsset('/images/intro-poster.png');

// Keep ref updated
useEffect(() => {
Expand Down Expand Up @@ -50,8 +53,8 @@ export function IntroVideo({ onComplete }: IntroVideoProps) {
>
<video
ref={videoRef}
src="/videos/intro.mp4"
poster="/images/intro-poster.png"
src={videoSrc}
poster={posterSrc}
preload="metadata"
className="max-w-full max-h-[80vh] object-contain"
onEnded={handleVideoEnd}
Expand Down
Loading
Loading