Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
ff67f3d
feat: add proUntil column
chedieck Jun 4, 2025
0aba51a
feat: add config options for pro
chedieck Jun 4, 2025
01f431a
refactor: organization title
chedieck Jun 4, 2025
8a50bfd
feat: component, service & endpoint to get pro status
chedieck Jun 4, 2025
e8ecc50
fix: mocked objects
chedieck Jun 4, 2025
4080778
refactor: rename ProConfig -> ProDisplay
chedieck Jun 4, 2025
d8631d7
feat: show ProDisplay and ProPurchase
chedieck Jun 4, 2025
d68460f
feat: pro settings skeleton
chedieck Jun 5, 2025
b3a35ae
chore: update default address
chedieck Jun 9, 2025
390c8e3
feat: make link button
chedieck Jun 10, 2025
24bdc53
fix: type on new config parameter
chedieck Jun 10, 2025
47561ab
chore: add new config parameters to README
chedieck Jun 10, 2025
e1325fa
fix: Upgrade to Pro text & css
chedieck Jun 12, 2025
a6943eb
feat: add hint
chedieck Jun 12, 2025
35508b1
fix: default export name
chedieck Jun 12, 2025
95167d6
fix: button link css
chedieck Jun 12, 2025
69f173e
fix latest to be 4.1.0
chedieck Jun 12, 2025
fcd7a4d
Merge branch 'master' into feat/pro-setting
chedieck Jun 12, 2025
4d0d746
refactor: update config and README
chedieck Jun 20, 2025
968a5b2
fix: update code to use new config
chedieck Jun 20, 2025
0336536
feat: informative table with limits
chedieck Jun 20, 2025
8a91569
fix: readme
chedieck Jun 20, 2025
26e1e0b
feat: invoices api
lissavxo May 26, 2025
8a1601d
feat: invoices modal
lissavxo May 26, 2025
1c3f7e5
refactor: clean up
lissavxo Jun 4, 2025
8784edd
fix: improve next invoice number method
lissavxo Jun 4, 2025
3141633
refactor: clean up
lissavxo Jun 5, 2025
7e87d8e
refactor: clean up
lissavxo Jun 10, 2025
8dc874e
feat: invoice transaction optional
lissavxo Jun 13, 2025
6dd4900
refactor: clean up
lissavxo Jun 18, 2025
b7efd58
feat: use prisma decimal
lissavxo Jun 19, 2025
8d385ba
fix: button detail for 0 txs
chedieck Jun 20, 2025
63fa2a2
fix: missing comma
chedieck Jul 18, 2025
a5db482
Merge branch 'master' into feat/pro-setting
chedieck Jul 18, 2025
9a03f88
Merge branch 'master' into feat/pro-setting
chedieck Jul 29, 2025
9b1e07f
refactor: prodisplay modal rewording
chedieck Aug 5, 2025
a1c80d1
refactor: display pro info all the time
chedieck Aug 5, 2025
57e8c01
chore: remove defaults from README.md
chedieck Aug 6, 2025
2930c90
chore: remove redundant type explanation
chedieck Aug 6, 2025
07ccc28
Merge branch 'master' into feat/pro-setting
chedieck Aug 6, 2025
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
77 changes: 57 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,46 +103,47 @@ The project includes several Make commands to manage Docker containers and devel

### Optional configuration

PayButton Server is configured with a `paybutton-config.json` file in the root of the repository. An example file can be find at [config/example-config.json](https://github.com/PayButton/paybutton-server/blob/master/config/example-config.json). The values it takes are:
PayButton Server is configured with a `paybutton-config.json` file in the root of the repository. An example file with the default values can be find at [config/example-config.json](https://github.com/PayButton/paybutton-server/blob/master/config/example-config.json). The values it takes are:

---

#### **apiDomain**
```
type: string
default: "http://localhost:3000/api",
```
> Base path for the API.


#### apiBasePath
```
type: string
default: "/api/auth"
```
> Base API endpoint for authentication.


#### websiteBasePath
```
type: string
```
> Base API endpoint for authentication through SuperTokens.

#### websiteDomain
```
type: string
default: "http://localhost:3000"
```
> Base path for the website.


#### wsBaseURL
```
type: string
default: "http://localhost:5000"
```
> Base path for the websocket server.


#### showTestNetworks
```
type: boolean
default: false,
```
> If the connection of test networks for eCash and Bitcoin Cash should appear in the Networks tab.

Expand All @@ -161,14 +162,12 @@ type: {
#### priceAPIURL
```
type: string
default: "https://coin.dance/api/"
```
> API to get prices from. Only coin.dance currently supported.

#### redisURL
```
type: string
default: "redis://paybutton-cache:6379"
```
> URL for the Redis server.

Expand All @@ -179,10 +178,6 @@ type: {
"ecash": "chronik",
"bitcoincash": "chronik"
}
default: {
"ecash": "chronik",
"bitcoincash": "chronik"
}
```
> Which client to use to get the blockchain information for each network. Currently, only "chronik" is supported for eCash and Bitcoin Cash.

Expand All @@ -193,44 +188,86 @@ type: {
"ecash": boolean
"bitcoincash": boolean
}

default: {
"bitcoincash": true
}
```
> What networks are currently under maintenance.


#### triggerPOSTTimeout
```
type: number
default: 3000
```
> How long a POST request triggered from a button payment will wait for an answer to be marked as successful.

#### smtpHost
```
type: string
default: N/A
```
> Host name for the server from which payment trigger emails will be sent. Not setting this up will result in email triggers not working.


#### smtpPort
```
type: number
default: N/A
```
> Port for the SMTP server from which payment trigger emails will be sent. Not setting this up will result in email triggers not working.


#### sideshiftAffiliateId
```
type: string
default: N/A
```
> Necessary only for paybutton client to interact with sideshift through the server.

#### proSettings
```
type: object
```
> General configuration for PayButton Pro. Each parameter is described below.

##### proSettings.enabled
```
type: boolean
```
> If the Pro feature should be enabled or hidden.

##### proSettings.monthsCost
```
type: {
[key: string]: number
}
```
> The pricing model for PayButton Pro subscription — [value] USD for [key] months.

##### proSettings.payoutAddress
```
type: string
```
> The payout address for PayButton Pro subscriptions.

##### proSettings.standardDailyEmailLimit
```
type: number | "Inf"
```
> How many emails can a standard user send daily.

##### proSettings.proDailyEmailLimit
```
type: number | "Inf"
```
> How many emails can a PayButton Pro user send daily.

##### proSettings.standardAddressesPerButtonLimit
```
type: number | "Inf"
```
> How many addresses can a standard Pro user add for a single button.

##### proSettings.proAddressesPerButtonLimit
```
type: number | "Inf"
```
> How many addresses can a PayButton Pro user add for a single button.

---

- For production, set `ENVIRONMENT=production` in `.env.local.` This optimizes the build for performance and skips the setup of various dev tools (like LiveReload).
Expand Down
76 changes: 76 additions & 0 deletions components/Account/ProDisplay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { useEffect, useState } from 'react'
import ProPurchase from './ProPurchase'
import style from './account.module.css'
import stylep from '../../pages/account/account.module.css'
import config from 'config/index'

const ProConfig = (): JSX.Element => {
const [text, setText] = useState('')
const [isPro, setIsPro] = useState<boolean | null>()

const showLimit = (configLimit: number | 'Inf'): string => {
return configLimit === 'Inf' ? 'Unlimited' : configLimit.toString()
}

useEffect(() => {
void (async () => {
const res = await fetch('/api/user/remainingProTime')
if (res.status === 200) {
const remainingMs: number | null = await res.json()
if (remainingMs === null) {
setIsPro(false)
setText('You are not PRO.')
} else if (remainingMs <= 0) {
setIsPro(false)
setText('Your PRO has expired.')
} else {
const futureDate = new Date(Date.now() + remainingMs)
setIsPro(true)
setText(`You are PRO until ${futureDate.toLocaleDateString()}.`)
}
} else {
setText('Failed to fetch PRO status')
}
})()
}, [])

return <>
<h3>PayButton Pro</h3>
<div className={style.pro_ctn}>
<div className={stylep.label}>
{text}
</div>
{isPro === false && <ProPurchase/>}
<div className={stylep.public_key_info_ctn}>
<table>
<thead>
<tr>
<th></th>
<th>Standard</th>
<th>Pro</th>
</tr>
</thead>
<tbody>
<tr>
<td>Outgoing Emails on Payment</td>
<td>{showLimit(config.proSettings.standardDailyEmailLimit)} / day</td>
<td>{showLimit(config.proSettings.proDailyEmailLimit)} / day</td>
</tr>
<tr>
<td>Addresses Per Button</td>
<td>{showLimit(config.proSettings.standardAddressesPerButtonLimit)}</td>
<td>{showLimit(config.proSettings.proAddressesPerButtonLimit)}</td>
</tr>
<tr>
<td>Outgoing Server-to-Server Messages On Payment</td>
<td>{showLimit(config.proSettings.standardDailyEmailLimit)} / day</td>
<td>{showLimit(config.proSettings.proDailyEmailLimit)} / day</td>
</tr>
</tbody>
</table>
</div>
</div>
</>
}

export default ProConfig
13 changes: 13 additions & 0 deletions components/Account/ProPurchase.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Button from 'components/Button'
import Link from 'next/link'
import style from './account.module.css'

const ProPurchase = (): JSX.Element => {
return <div className={style.upgrade_btn}>
<Link href='/pro'>
<Button>Upgrade to Pro</Button>
</Link>
</div>
}

export default ProPurchase
30 changes: 30 additions & 0 deletions components/Account/account.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,33 @@ body[data-theme='dark'] .changepw_ctn input {
}
}

.pro_ctn {
width: 100%;
background-color: #fff;
max-width: 700px;
padding: 20px;
border-radius: 10px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
}

body[data-theme="dark"] .pro_ctn {
background-color: var(--secondary-bg-color);
}

body[data-theme="dark"] .pro_ctn input {
border-color: var(--gray)
}

.upgrade_btn {
margin-top: 2rem;
width: 100%
}
.upgrade_btn a {
width: 100%
}
.upgrade_btn a button {
width: 100%
}
2 changes: 1 addition & 1 deletion components/Button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ interface ButtonProps {
loading?: boolean
}

export default function TopBar ({
export default function Button ({
children,
disabled,
type = 'button',
Expand Down
5 changes: 3 additions & 2 deletions components/Organization/ViewOrganization.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ const ViewOrganization = ({ user, orgMembers, setOrgMembers, organization }: IPr
const [orgEdit, setOrgEdit] = useState('')
const [loading, setLoading] = useState(false)

return (
return <>
<h3 className={style.config_title}>Organization</h3>
<div className={style.org_ctn}>
{org !== null && org.creatorId === user.userProfile.id
? (
Expand Down Expand Up @@ -129,7 +130,7 @@ const ViewOrganization = ({ user, orgMembers, setOrgMembers, organization }: IPr
)}
{error !== '' && <div className={style.error_message}>{error}</div>}
</div>
)
</>
}

export default ViewOrganization
16 changes: 15 additions & 1 deletion config/example-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,19 @@
"bitcoincash": true
},
"triggerPOSTTimeout": 3000,
"sideshiftAffiliateId": "JPk84U3xN"
"sideshiftAffiliateId": "JPk84U3xN",
"proSettings": {
"enabled": true,
"monthsCost": {
"1": 10,
"3": 20,
"6": 30,
"12": 50
},
"payoutAddress": "ecash:qrf4zh4vgrdal8d8gu905d90w5u2y60djcd2d5h6un",
"standardDailyEmailLimit": 5,
"proDailyEmailLimit": 100,
"standardAddressesPerButtonLimit": 20,
"proAddressesPerButtonLimit": "Inf"
}
}
13 changes: 13 additions & 0 deletions config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@ import localConfig from '../paybutton-config.json'

export type BlockchainClientOptions = 'grpc' | 'chronik'

interface ProSettings {
enabled: boolean
monthsCost: {
[key: string]: number
}
payoutAddress: string
standardDailyEmailLimit: number | 'Inf'
proDailyEmailLimit: number | 'Inf'
standardAddressesPerButtonLimit: number | 'Inf'
proAddressesPerButtonLimit: number | 'Inf'
}

interface Config {
appName: string
apiDomain: string
Expand All @@ -21,6 +33,7 @@ interface Config {
sideshiftAffiliateId: string
smtpHost: string
smtpPort: number
proSettings: ProSettings
}

const readConfig = (): Config => {
Expand Down
Loading