Skip to content

Commit

Permalink
Merge branch 'main' into rp--open-payments-sdk
Browse files Browse the repository at this point in the history
  • Loading branch information
raducristianpopa committed Feb 20, 2024
2 parents f60ef44 + b944898 commit 2d633fc
Show file tree
Hide file tree
Showing 31 changed files with 536 additions and 106 deletions.
37 changes: 28 additions & 9 deletions src/background/Background.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,60 @@
import { bytesToHex } from '@noble/hashes/utils'
import { runtime, tabs } from 'webextension-polyfill'
import browser, { Runtime, runtime, tabs } from 'webextension-polyfill'

import { type PaymentFlowService } from '@/background/paymentFlow'
import { exportJWK, generateEd25519KeyPair } from '@/utils/crypto'
import { defaultData } from '@/utils/storage'

import getSendingPaymentPointerHandler from '../messageHandlers/getSendingPaymentPointerHandler'
import getStorageData from '../messageHandlers/getStorageData'
import isMonetizationReadyHandler from '../messageHandlers/isMonetizationReadyHandler'
import runPaymentHandler from '../messageHandlers/runPaymentHandler'
import setIncomingPointerHandler from '../messageHandlers/setIncomingPointerHandler'
import { tabChangeHandler, tabUpdateHandler } from './tabHandlers'

const storage = browser.storage.local

class Background {
private messageHandlers: any = [
isMonetizationReadyHandler,
setIncomingPointerHandler,
getSendingPaymentPointerHandler,
runPaymentHandler,
getStorageData,
]
private subscriptions: any = []
// TO DO: remove these from background into storage or state & use injection
grantFlow: PaymentFlowService | null = null
spentAmount: number = 0
paymentStarted = false

constructor() {}
constructor() {
storage
.set({ data: defaultData })
.then(() => console.log('Default data stored successfully'))
.catch((error: any) => console.error('Error storing data:', error))
}

subscribeToMessages() {
this.subscriptions = this.messageHandlers.map((handler: any) => {
const listener: any = async (message: EXTMessage) => {
const listener: any = (
message: EXTMessage,
sender: Runtime.MessageSender,
sendResponse: (_res: any) => void,
) => {
if (handler.type === message.type) {
try {
await handler.callback(message.data, this)
} catch (error) {
console.log('[===== Error in MessageListener =====]', error)
return error
}
handler
.callback(message.data, this)
.then((res: any) => {
sendResponse(res)
})
.catch((error: any) => {
console.log('[===== Error in MessageListener =====]', error)
sendResponse(error)
})
}

return true
}

runtime.onMessage.addListener(listener)
Expand Down
30 changes: 30 additions & 0 deletions src/components/__tests__/code.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { fireEvent, render } from '@testing-library/react'
import React from 'react'

import { Code } from '../code'

describe('Code', () => {
it('should render the code component', () => {
const { queryByRole, container } = render(<Code value="test" />)
const code = container.querySelector('code')

expect(code).toBeInTheDocument()
expect(code).toHaveTextContent('test')
expect(queryByRole('button')).toHaveAttribute('aria-label', 'copy')
})

it('calls clipboard.writeText with the correct value', () => {
Object.assign(navigator, {
clipboard: {
writeText: jest.fn(),
},
})

const { getByRole } = render(<Code value="test" />)
const copyButton = getByRole('button')
expect(copyButton).toBeInTheDocument()

fireEvent.click(copyButton)
expect(navigator.clipboard.writeText).toHaveBeenCalledWith('test')
})
})
2 changes: 2 additions & 0 deletions src/components/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ const buttonVariants = cva(
variant: {
default: 'bg-button-base text-white hover:bg-button-base-hover',
destructive: 'bg-error text-error hover:bg-error-hover',
ghost: '',
},
size: {
default: 'py-4 px-6 font-medium',
icon: 'h-6 w-6',
},
fullWidth: {
true: 'w-full',
Expand Down
55 changes: 55 additions & 0 deletions src/components/code.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React from 'react'

import { cn } from '@/utils/cn'

import { Button } from './button'
import { CheckIcon, ClipboardIcon } from './icons'

interface CodeProps extends React.HTMLAttributes<HTMLDivElement> {
value: string
}

export const Code = ({ value, className, ...props }: CodeProps) => {
return (
<div
className={cn(
'flex items-center justify-between gap-x-2 rounded-xl bg-nav-active p-4 text-medium break-all',
className,
)}
{...props}>
<code>{value}</code>
<CopyButton value={value} />
</div>
)
}

interface CopyButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
value: string
}

const CopyButton = ({ value, ...props }: CopyButtonProps) => {
const [hasCopied, setHasCopied] = React.useState(false)

React.useEffect(() => {
if (hasCopied === true) {
setTimeout(() => {
setHasCopied(false)
}, 2000)
}
}, [hasCopied])

return (
<Button
{...props}
aria-label="copy"
variant="ghost"
size="icon"
className="text-primary rounded-sm"
onClick={() => {
navigator.clipboard.writeText(value)
setHasCopied(true)
}}>
{hasCopied ? <CheckIcon className="h-6 w-6" /> : <ClipboardIcon className="h-6 w-6" />}
</Button>
)
}
61 changes: 61 additions & 0 deletions src/components/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,64 @@ export const DollarSign = (props: React.SVGProps<SVGSVGElement>) => {
</svg>
)
}

export const WarningSign = (props: React.SVGProps<SVGSVGElement>) => {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}>
<mask
id="mask0_140_3633"
style={{ maskType: 'alpha' }}
maskUnits="userSpaceOnUse"
x="0"
y="0"
width="24"
height="24">
<rect width="24" height="24" fill="#C4C4C4" />
</mask>
<g mask="url(#mask0_140_3633)">
<path
d="M11 13H13V7H11V13ZM12 17C12.2833 17 12.521 16.904 12.713 16.712C12.9043 16.5207 13 16.2833 13 16C13 15.7167 12.9043 15.479 12.713 15.287C12.521 15.0957 12.2833 15 12 15C11.7167 15 11.4793 15.0957 11.288 15.287C11.096 15.479 11 15.7167 11 16C11 16.2833 11.096 16.5207 11.288 16.712C11.4793 16.904 11.7167 17 12 17ZM12 22C10.6167 22 9.31667 21.7373 8.1 21.212C6.88333 20.6873 5.825 19.975 4.925 19.075C4.025 18.175 3.31267 17.1167 2.788 15.9C2.26267 14.6833 2 13.3833 2 12C2 10.6167 2.26267 9.31667 2.788 8.1C3.31267 6.88333 4.025 5.825 4.925 4.925C5.825 4.025 6.88333 3.31233 8.1 2.787C9.31667 2.26233 10.6167 2 12 2C13.3833 2 14.6833 2.26233 15.9 2.787C17.1167 3.31233 18.175 4.025 19.075 4.925C19.975 5.825 20.6873 6.88333 21.212 8.1C21.7373 9.31667 22 10.6167 22 12C22 13.3833 21.7373 14.6833 21.212 15.9C20.6873 17.1167 19.975 18.175 19.075 19.075C18.175 19.975 17.1167 20.6873 15.9 21.212C14.6833 21.7373 13.3833 22 12 22ZM12 20C14.2167 20 16.1043 19.221 17.663 17.663C19.221 16.1043 20 14.2167 20 12C20 9.78333 19.221 7.89567 17.663 6.337C16.1043 4.779 14.2167 4 12 4C9.78333 4 7.896 4.779 6.338 6.337C4.77933 7.89567 4 9.78333 4 12C4 14.2167 4.77933 16.1043 6.338 17.663C7.896 19.221 9.78333 20 12 20Z"
fill="#EF4444"
/>
</g>
</svg>
)
}

export const ClipboardIcon = (props: React.SVGProps<SVGSVGElement>) => {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}>
<path
d="M9 18C8.45 18 7.97933 17.8043 7.588 17.413C7.196 17.021 7 16.55 7 16V4C7 3.45 7.196 2.979 7.588 2.587C7.97933 2.19567 8.45 2 9 2H18C18.55 2 19.021 2.19567 19.413 2.587C19.8043 2.979 20 3.45 20 4V16C20 16.55 19.8043 17.021 19.413 17.413C19.021 17.8043 18.55 18 18 18H9ZM9 16H18V4H9V16ZM5 22C4.45 22 3.979 21.8043 3.587 21.413C3.19567 21.021 3 20.55 3 20V6H5V20H16V22H5Z"
fill="currentColor"
/>
</svg>
)
}

export const CheckIcon = (props: React.SVGProps<SVGSVGElement>) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="w-6 h-6"
{...props}>
<path strokeLinecap="round" strokeLinejoin="round" d="m4.5 12.75 6 6 9-13.5" />
</svg>
)
}
12 changes: 12 additions & 0 deletions src/components/layout/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { runtime } from 'webextension-polyfill'

import { ArrowBack, Settings } from '../icons'
import { ROUTES } from '../router-provider'
import { usePopup } from '@/providers/popup.state'
import { Switch } from '../switch'

const Logo = runtime.getURL('assets/images/logo.svg')

Expand All @@ -29,6 +31,15 @@ const NavigationButton = () => {
}

export const Header = () => {
const {
data: { wmEnabled },
setData,
} = usePopup()

const switchWmEnabled = () => {
setData(prevState => ({ ...prevState, wmEnabled: !prevState.wmEnabled }))
}

return (
<div className="flex flex-row items-center justify-between py-8">
<div className="flex flex-row items-center">
Expand All @@ -37,6 +48,7 @@ export const Header = () => {
</div>
<div className="flex flex-row items-center">
<NavigationButton />
<Switch checked={wmEnabled} onChange={switchWmEnabled} className="ml-2" />
</div>
</div>
)
Expand Down
13 changes: 11 additions & 2 deletions src/components/radio-group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export interface RadioGroupProps
disabled?: boolean
items: Omit<RadioProps, 'name'>[]
name: string
handleChange?: (value: string) => void
}

export const RadioGroup = ({
Expand All @@ -95,8 +96,13 @@ export const RadioGroup = ({
fullWidth,
disabled,
className,
handleChange,
value,
}: RadioGroupProps) => {
const checkedItem = useMemo(() => items.findIndex(item => item.checked), [items])
const checkedItem = useMemo(
() => items.findIndex(item => item.checked || item.value === value),
[items, value],
)
const [selected, setSelected] = useState(checkedItem)

const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
Expand Down Expand Up @@ -140,7 +146,10 @@ export const RadioGroup = ({
disabled={disabled}
checked={selected === index}
noSelected={selected === -1 && index === 0}
onChange={() => setSelected(index)}
onChange={() => {
setSelected(index)
if (handleChange) handleChange(item.value)
}}
/>
))}
</div>
Expand Down
5 changes: 4 additions & 1 deletion src/components/switch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ export interface SwitchProps
extends VariantProps<typeof switchVariants>,
React.HTMLAttributes<HTMLInputElement> {
checked?: boolean
onChange?: (_event: React.ChangeEvent<HTMLInputElement>) => void
}

export const Switch = forwardRef<HTMLInputElement, SwitchProps>(function Switch(
{ size, className, ...props },
{ size, className, onChange = () => {}, ...props },
ref,
) {
return (
Expand All @@ -45,6 +46,8 @@ export const Switch = forwardRef<HTMLInputElement, SwitchProps>(function Switch(
role="switch"
ref={ref}
type="checkbox"
checked={props.checked}
onChange={onChange}
{...props}
className="peer absolute opacity-0 -translate-x-[100%] pointer-events-none"
/>
Expand Down
14 changes: 14 additions & 0 deletions src/content/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { runtime } from 'webextension-polyfill'

import { initMonetizationTagManager } from '@/utils/monetizationTagManager'

import { loadObserver } from './linksObserver'
import MessageListener from './messageListener'

runtime.onMessage.addListener(MessageListener)

// DEBUG PURPOSE
loadObserver()

// TBD - check logic
initMonetizationTagManager()
26 changes: 0 additions & 26 deletions src/content/index.tsx

This file was deleted.

15 changes: 7 additions & 8 deletions src/content/messageListener.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
// import { Runtime } from 'webextension-polyfill'

import { PaymentSender } from '@/content/monetization'

const paymentSender = new PaymentSender()

export const onRequest = async (
msg: EXTMessage,
// sender: Runtime.SendMessageOptionsType,
): Promise<EXTResponse | undefined> => {
// console.log('~~~~~~~', msg)

export const onRequest = async (msg: EXTMessage): Promise<EXTResponse | undefined> => {
switch (msg.type) {
case 'LOAD': {
const monetizationTag = document.querySelector('link[rel="monetization"]')
monetizationTag?.dispatchEvent(new Event('load'))
break
}

case 'IS_MONETIZATION_READY': {
const monetizationTag = document.querySelector('link[rel="monetization"]')

Expand Down
Loading

0 comments on commit 2d633fc

Please sign in to comment.