Skip to content

Commit

Permalink
feat: Active WebMo Page UI (#107)
Browse files Browse the repository at this point in the history
webmo ui
  • Loading branch information
ionutanin authored Feb 27, 2024
1 parent 5cad493 commit 4146781
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 218 deletions.
10 changes: 5 additions & 5 deletions src/components/layout/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ export const Header = () => {
}

return (
<div className="flex flex-row items-center justify-between py-8">
<div className="flex flex-row items-center">
<div className="flex flex-row items-center justify-between h-8">
<div className="flex flex-row items-center gap-3">
<img src={Logo} alt="Web Monetization Logo" className="h-6" />
<p className="ml-3 text-strong text-xl">Web Monetization</p>
<p className="text-strong text-xl">Web Monetization</p>
</div>
<div className="flex flex-row items-center">
<div className="flex flex-row items-center gap-3">
<NavigationButton />
<Switch checked={wmEnabled} onChange={switchWmEnabled} className="ml-2" />
<Switch checked={wmEnabled} onChange={switchWmEnabled} />
</div>
</div>
)
Expand Down
4 changes: 2 additions & 2 deletions src/components/layout/main-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import { Outlet } from 'react-router-dom'
import { Header } from './header'

const Divider = () => {
return <div className="mb-8 bg-divider-gradient w-100 h-1" />
return <div className="bg-divider-gradient w-100 h-1" />
}

export const MainLayout = () => {
return (
<div className="flex flex-col w-popup h-popup border-base px-6">
<div className="flex flex-col gap-8 w-popup h-popup border-base px-6 pt-8">
<Header />
<Divider />
<main>
Expand Down
3 changes: 2 additions & 1 deletion src/components/slider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const sliderClasses = `
[&::-moz-range-thumb]:h-5
[&::-moz-range-thumb]:bg-switch-base
[&::-moz-range-thumb]:rounded-full
[&::-webkit-slider-thumb]:disabled:bg-disabled-strong
w-full h-1 bg-disabled-strong rounded-lg
appearance-none cursor-pointer dark:bg-disabled-strong
`
Expand All @@ -42,7 +43,7 @@ export const Slider = forwardRef<HTMLInputElement, SliderProps>(function Slider(
aria-disabled={disabled ?? false}
aria-invalid={!!errorMessage}
aria-describedby={errorMessage}
value={value}
value={disabled ? 0 : value}
onChange={onChange}
{...props}
/>
Expand Down
15 changes: 1 addition & 14 deletions src/popup/Popup.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ body {
width: fit-content;
height: fit-content;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
font-family: 'Titillium Web', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
Expand All @@ -28,19 +28,6 @@ body {
box-sizing: border-box;
}

.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex-basis: auto;
padding: 0 20px 10px;

img {
height: 96px;
}
}

.pointerForm {
width: 100%;
border-radius: 8px;
Expand Down
5 changes: 4 additions & 1 deletion src/popup/index.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
<!DOCTYPE html>
<html>
<html lang="en">

<head>
<title>
<%= htmlWebpackPlugin.options.title %>
</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Titillium+Web:wght@400;500;700&display=swap" rel="stylesheet">
</head>

<body>
Expand Down
258 changes: 65 additions & 193 deletions src/popup/pages/Home.tsx
Original file line number Diff line number Diff line change
@@ -1,212 +1,84 @@
import React, { useEffect, useState } from 'react'
import { runtime } from 'webextension-polyfill'
import React, { useState } from 'react'

import { Button } from '@/components/button'
import { DollarSign, WarningSign } from '@/components/icons'
import { Input } from '@/components/input'
import { Label } from '@/components/label'
import { Slider } from '@/components/slider'
import { Switch } from '@/components/switch'
import { usePopup } from '@/providers/popup.state'
import { formatCurrency } from '@/utils/formatCurrency'
import { sendMessage, sendMessageToActiveTab } from '@/utils/sendMessages'
import { getStorageKey } from '@/utils/storage'

const Success = runtime.getURL('assets/images/web-monetization-success.svg')
const Fail = runtime.getURL('assets/images/web-monetization-fail.svg')
const CheckIcon = runtime.getURL('assets/images/check.svg')
const DollarIcon = runtime.getURL('assets/images/dollar.svg')
const CloseIcon = runtime.getURL('assets/images/close.svg')

// --- Temporary code until real UI implemented ---

interface IProps {
isMonetizationReady: boolean
}

const PopupFooter: React.FC<IProps> = ({ isMonetizationReady }) => (
<footer className="flex items-center justify-center px-4">
{isMonetizationReady ? (
<span>This site is Web Monetization ready</span>
) : (
<span>This site isn&apos;t Web Monetization ready</span>
)}
</footer>
)

// --- End of Temporary code until real UI implemented ---

export const Home = () => {
const [remainingBalance, setRemainingBalance] = useState(0)
const [rateOfPay, setRateOfPay] = useState(0.36)
const [loading, setLoading] = useState(false)
const [paymentStarted, setPaymentStarted] = useState(false)
const [spent, setSpent] = useState(0)
const [sendingPaymentPointer, setSendingPaymentPointer] = useState('')
const [isMonetizationReady, setIsMonetizationReady] = useState(false)
const [receivingPaymentPointer, setReceivingPaymentPointer] = useState('')
const [formData, setFormData] = useState({
paymentPointer: sendingPaymentPointer || '',
amount: 0,
})

useEffect(() => {
checkMonetizationReady()
getSendingPaymentPointer()
listenForIncomingPayment()
getRateOfPay()
getRemainingBalance()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

const getRateOfPay = async () => {
const response = await getStorageKey('rateOfPay')
response && setRateOfPay(response)
}

const getRemainingBalance = async () => {
const response = await getStorageKey('amount')
response && setRemainingBalance(response)
}

const checkMonetizationReady = async () => {
const response = await sendMessageToActiveTab({ type: 'IS_MONETIZATION_READY' })
setIsMonetizationReady(response.data.monetization)
setReceivingPaymentPointer(response.data.paymentPointer)
}

const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setFormData(prevState => ({ ...prevState, [event.target.name]: event.target.value }))
}

const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault()

setLoading(true)
const data = {
amount: formData.amount,
paymentPointer: formData.paymentPointer,
incomingPayment: receivingPaymentPointer,
}
const {
data: { wmEnabled, rateOfPay, amount, amountType },
setData,
} = usePopup()
const [tipAmount, setTipAmount] = useState('')

await sendMessage({ type: 'SET_INCOMING_POINTER', data })
}

const getSendingPaymentPointer = async () => {
const response = await sendMessage({ type: 'GET_SENDING_PAYMENT_POINTER' })
setSendingPaymentPointer(response.data.sendingPaymentPointerUrl)

const { sendingPaymentPointerUrl: paymentPointer, amount } = response.data
if (paymentPointer && amount) {
setFormData({
paymentPointer: response.data.sendingPaymentPointerUrl,
amount: response.data.amount,
})
}
}

const listenForIncomingPayment = async () => {
const listener = (message: any) => {
if (message.type === 'SPENT_AMOUNT') {
setSpent(message.data.spentAmount)
setPaymentStarted(true)
}

if (loading) {
setLoading(false)
}
}

runtime.onMessage.addListener(listener)
return () => {
runtime.onMessage.removeListener(listener)
}
const updateRateOfPay = async (event: any) => {
setData(prevState => ({ ...prevState, rateOfPay: event.target.value }))
}

const stopPayments = async (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
e.preventDefault()
setPaymentStarted(false)
setTimeout(() => {
if (loading) {
setLoading(false)
}
}, 1000)
await sendMessageToActiveTab({ type: 'STOP_PAYMENTS' })
const updateStreamType = async (event: any) => {
setData(prevState => ({
...prevState,
amountType: { ...prevState.amountType, recurring: event.target.checked },
}))
}

const updateRateOfPay = async (event: any) => {
setRateOfPay(event.target.value)
await sendMessage({
type: 'SET_STORAGE_KEY',
data: { key: 'rateOfPay', value: event.target.value },
})
if (!wmEnabled) {
return (
<div className="flex items-center gap-2">
<WarningSign />
<p className="text-base text-medium">Web Monetization has been turned off.</p>
</div>
)
}

return (
<>
{!!spent && (
<div className="spentAmount">
${spent}/<span>$20</span>
<div className="flex flex-col gap-8 basis-auto justify-center">
<div className="grid gap-4 w-full">
<div className="px-2 text-base font-medium text-medium">Current rate of pay</div>
<Slider
min={0}
max={1}
step={0.01}
value={rateOfPay}
onChange={updateRateOfPay}
disabled={!amountType.recurring}
/>
<div className="px-2 flex items-center justify-between w-full">
<span>{!amountType.recurring ? '0c' : formatCurrency(rateOfPay)} per hour</span>
<span>Remaining balance: ${amount}</span>
</div>
)}
<div className="content">
<div className="grid gap-4 w-full">
<div className="px-2 text-base font-medium text-medium">Current rate of pay</div>
<Slider min={0} max={1} step={0.01} value={rateOfPay} onChange={updateRateOfPay} />
<div className="flex items-center justify-between w-full">
<span>{formatCurrency(rateOfPay)} per hour</span>
<span>Remaining balance: ${remainingBalance}</span>
</div>
</div>

{isMonetizationReady ? (
<>
<img src={Success} alt="Success" />

<form
onSubmit={handleSubmit}
className={`pointerForm ${paymentStarted ? 'active' : ''}`}>
<div className="input-wrapper">
<label htmlFor="paymentPointer">Payment pointer</label>
<div className="input">
<input
type="text"
name="paymentPointer"
value={formData.paymentPointer}
onInput={handleChange}
disabled={paymentStarted}
placeholder="https://ilp.rafiki.money/alice"
/>
</div>
</div>
</div>

<div className="input-wrapper">
<label htmlFor="pointer">Amount</label>
<div className="input">
<img src={DollarIcon} alt="dollar" />
<input
type="text"
name="amount"
value={formData.amount}
onInput={handleChange}
disabled={paymentStarted}
placeholder="0.05"
/>
</div>
</div>
<div className="flex items-center gap-4 h-7">
<Switch size="small" checked={amountType.recurring} onChange={updateStreamType} />
<span className="text-medium text-base">Continuous payments stream</span>
</div>

<div className="actions">
{paymentStarted ? (
<button type="button" className="stop-btn" onClick={stopPayments}>
<img src={CloseIcon} alt="Stop" />
</button>
) : (
<button type="submit" className={`submit-btn ${loading ? 'loading' : ''}`}>
<img src={CheckIcon} alt="Check" />
</button>
)}
</div>
</form>
</>
) : (
<img src={Fail} alt="Fail" />
)}
<div className="h-px bg-nav-active" />

<div className="flex flex-col gap-4">
<Label className="text-base font-medium text-medium">
Pay <span className="text-primary">https://alexlakatos.com/</span>
</Label>
<Input
value={tipAmount}
type="number"
id="amount"
name="amount"
placeholder="0.00"
onChange={event => setTipAmount(event.target.value)}
icon={<DollarSign />}
/>
</div>
<PopupFooter isMonetizationReady={isMonetizationReady} />
</>

<Button aria-label="Send now" className="text-base font-medium">
Send now
</Button>
</div>
)
}
4 changes: 2 additions & 2 deletions src/popup/pages/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ export const Settings = () => {

if (!wmEnabled)
return (
<div className="flex items-center">
<div className="flex items-center gap-2">
<WarningSign />
<p className="text-medium text-medium pl-2">Web Monetization has been turned off.</p>
<p className="text-base text-medium">Web Monetization has been turned off.</p>
</div>
)

Expand Down

0 comments on commit 4146781

Please sign in to comment.