Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
rolznz committed Dec 28, 2023
0 parents commit dd400c8
Show file tree
Hide file tree
Showing 23 changed files with 2,365 additions and 0 deletions.
18 changes: 18 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
}
51 changes: 51 additions & 0 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Simple workflow for deploying static content to GitHub Pages
name: Deploy static content to Pages

on:
# Runs on pushes targeting the default branch
push:
branches: ["master"]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

# Sets the GITHUB_TOKEN permissions to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write

# Allow one concurrent deployment
concurrency:
group: "pages"
cancel-in-progress: true

jobs:
# Single deploy job since we're just deploying
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Node
uses: actions/setup-node@v3
with:
node-version: 18
cache: "yarn"
- name: Install dependencies
run: yarn install
- name: Build
run: yarn build
- name: Setup Pages
uses: actions/configure-pages@v3
- name: Upload artifact
uses: actions/upload-pages-artifact@v2
with:
# Upload dist repository
path: "./dist"
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v2
24 changes: 24 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Alby PoS

Static HTML PoS powered by Nostr Wallet Connect

## Development

`yarn install`
`yarn dev`
13 changes: 13 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Alby PoS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
35 changes: 35 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "pos",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"@getalby/bitcoin-connect-react": "^3.1.1",
"@getalby/sdk": "^3.2.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.21.1"
},
"devDependencies": {
"@types/react": "^18.2.43",
"@types/react-dom": "^18.2.17",
"@typescript-eslint/eslint-plugin": "^6.14.0",
"@typescript-eslint/parser": "^6.14.0",
"@vitejs/plugin-react-swc": "^3.5.0",
"autoprefixer": "^10.4.16",
"daisyui": "^4.4.20",
"eslint": "^8.55.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.5",
"postcss": "^8.4.32",
"tailwindcss": "^3.3.6",
"typescript": "^5.2.2",
"vite": "^5.0.8"
}
}
6 changes: 6 additions & 0 deletions postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
30 changes: 30 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { BrowserRouter, Route, Routes } from "react-router-dom";
import { Home } from "./pages/Home";
import { Wallet } from "./pages/Wallet";
import { NotFound } from "./pages/NotFound";
import { New } from "./pages/wallet/New";
import { Pay } from "./pages/wallet/Pay";
import { Paid } from "./pages/wallet/Paid";

function App() {
return (
<div
data-theme="bumblebee"
className="flex flex-col justify-start items-center w-full min-h-full p-8 font-sans"
>
<BrowserRouter basename="/pos">
<Routes>
<Route path="/" Component={Home} />
<Route path="/wallet/:nwcUrl" Component={Wallet}>
<Route path="new" Component={New} />
<Route path="pay/:invoice" Component={Pay} />
<Route path="paid" Component={Paid} />
</Route>
<Route path="/*" Component={NotFound} />
</Routes>
</BrowserRouter>
</div>
);
}

export default App;
Binary file added src/assets/alby.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

#root,
html,
body {
width: 100%;
height: 100%;
}
10 changes: 10 additions & 0 deletions src/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
70 changes: 70 additions & 0 deletions src/pages/Home.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import {
Button,
closeModal,
disconnect,
init,
WebLNProviders,
} from "@getalby/bitcoin-connect-react";
import albyImage from "../assets/alby.png";
import React from "react";
import { useNavigate } from "react-router-dom";

export function Home() {
React.useEffect(() => {
// TODO: allow specifying the NWC methods in advance
init({
filters: ["nwc"],
});
disconnect();
}, []);

const navigate = useNavigate();

return (
<>
<div className="flex flex-col justify-center items-center max-w-lg w-full">
<h1 className="text-2xl mb-4 font-bold">Alby PoS</h1>
<div className="flex justify-center items-center gap-4 mb-8">
<img src={albyImage} className="w-16 h-16 rounded" />
</div>
<p className="text-center mb-4">
Connect your wallet and only choose permissions to get info, receive
and lookup invoices to ensure you can only receive payments.
</p>
<Button
onConnected={async (provider) => {
try {
const info = await provider.getInfo();
if (
info.methods.length > 3 ||
info.methods.indexOf("makeInvoice") < 0 ||
info.methods.indexOf("lookupInvoice") < 0 ||
info.methods.indexOf("getInfo") < 0
) {
throw new Error(
"This provider must support exactly NWC getInfo, makeInvoice and lookupInvoice. Supports: " +
info.methods.join(",")
);
}
if (!(provider instanceof WebLNProviders.NostrWebLNProvider)) {
throw new Error(
"WebLN provider is not an instance of NostrWebLNProvider"
);
}
// TODO: below line should not be needed when modal is updated to close automatically after connecting
closeModal();
navigate(
`/wallet/${encodeURIComponent(
provider.nostrWalletConnectUrl
)}/new`
);
} catch (error) {
console.error(error);
alert(error);
}
}}
/>
</div>
</>
);
}
10 changes: 10 additions & 0 deletions src/pages/NotFound.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export function NotFound() {
return (
<>
<h1>404</h1>
<p>
<a href="/">Return Home</a>
</p>
</>
);
}
42 changes: 42 additions & 0 deletions src/pages/Wallet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { webln } from "@getalby/sdk";
import React from "react";
import { Outlet, useNavigate, useParams } from "react-router-dom";

export function Wallet() {
const { nwcUrl } = useParams();

const [provider, setProvider] = React.useState<
webln.NostrWebLNProvider | undefined
>();
const navigate = useNavigate();

React.useEffect(() => {
(async () => {
if (nwcUrl) {
try {
console.log("Enabling provider");
const _provider = new webln.NostrWebLNProvider({
nostrWalletConnectUrl: nwcUrl,
});

await _provider.enable();
setProvider(_provider);
} catch (error) {
console.error(error);
alert("Failed to load wallet: " + error);
}
}
})();
}, [nwcUrl]);

if (!nwcUrl) {
navigate("/");
return null;
}
if (!provider) {
// TODO: loading
return null;
}

return <Outlet context={provider} />;
}
50 changes: 50 additions & 0 deletions src/pages/wallet/New.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { webln } from "@getalby/sdk";
import React, { FormEvent } from "react";
import { useNavigate, useOutletContext } from "react-router-dom";

export function New() {
const [amount, setAmount] = React.useState("");
const navigate = useNavigate();
const provider = useOutletContext() as webln.NostrWebLNProvider;

async function onSubmit(e: FormEvent) {
e.preventDefault();
try {
const amountSats = parseInt(amount);
if (isNaN(amountSats) || amountSats < 1) {
throw new Error("Invalid amount: " + amountSats);
}

const invoice = await provider.makeInvoice({
amount: amountSats,
defaultMemo: "Alby PoS",
});
navigate(`../pay/${invoice.paymentRequest}`);
} catch (error) {
console.error(error);
alert("Failed to create invoice: " + error);
}
}

return (
<>
<form
onSubmit={onSubmit}
className="flex flex-col justify-center items-center h-full flex-1"
>
<div className="flex-1 flex flex-col justify-center items-center">
<p className="mb-4">Amount (sats)</p>
<input
className="input input-ghost text-6xl text-center"
placeholder="0"
value={amount}
onChange={(e) => setAmount(e.target.value)}
></input>
</div>
<button className="btn btn-primary w-full" type="submit">
Continue
</button>
</form>
</>
);
}
Loading

0 comments on commit dd400c8

Please sign in to comment.