From 5d4abecf3cb8cf662818731ba4275071afc449d5 Mon Sep 17 00:00:00 2001 From: ekzyis Date: Tue, 13 Sep 2022 01:18:23 +0200 Subject: [PATCH 1/8] Add input for fiat currency in settings --- api/typeDefs/user.js | 3 ++- fragments/users.js | 3 +++ pages/settings.js | 9 +++++++-- .../20220913010100_fiat_currency/migration.sql | 2 ++ prisma/schema.prisma | 1 + 5 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 prisma/migrations/20220913010100_fiat_currency/migration.sql diff --git a/api/typeDefs/user.js b/api/typeDefs/user.js index 86fde278..f1250204 100644 --- a/api/typeDefs/user.js +++ b/api/typeDefs/user.js @@ -29,7 +29,7 @@ export default gql` extend type Mutation { setName(name: String!): Boolean - setSettings(tipDefault: Int!, noteItemSats: Boolean!, noteEarning: Boolean!, + setSettings(tipDefault: Int!, fiatCurrency: String!, noteItemSats: Boolean!, noteEarning: Boolean!, noteAllDescendants: Boolean!, noteMentions: Boolean!, noteDeposits: Boolean!, noteInvites: Boolean!, noteJobIndicator: Boolean!, hideInvoiceDesc: Boolean!): User setPhoto(photoId: ID!): Int! @@ -58,6 +58,7 @@ export default gql` hasNewNotes: Boolean! hasInvites: Boolean! tipDefault: Int! + fiatCurrency: String bio: Item bioId: Int photoId: Int diff --git a/fragments/users.js b/fragments/users.js index 93ae84a4..60b9f89e 100644 --- a/fragments/users.js +++ b/fragments/users.js @@ -13,6 +13,7 @@ export const ME = gql` freeComments hasNewNotes tipDefault + fiatCurrency bioId hasInvites upvotePopover @@ -39,6 +40,7 @@ export const ME_SSR = gql` freePosts freeComments tipDefault + fiatCurrency bioId upvotePopover tipPopover @@ -57,6 +59,7 @@ export const ME_SSR = gql` export const SETTINGS_FIELDS = gql` fragment SettingsFields on User { tipDefault + fiatCurrency noteItemSats noteEarning noteAllDescendants diff --git a/pages/settings.js b/pages/settings.js index 2d260192..100bd4d1 100644 --- a/pages/settings.js +++ b/pages/settings.js @@ -54,6 +54,7 @@ export default function Settings ({ data: { settings } }) {
{ - await setSettings({ variables: { tipDefault: Number(tipDefault), ...values } }) + onSubmit={async ({ tipDefault, fiatCurrency, ...values }) => { + await setSettings({ variables: { tipDefault: Number(tipDefault), fiatCurrency, ...values } }) setSuccess('settings saved') }} > @@ -77,6 +78,10 @@ export default function Settings ({ data: { settings } }) { autoFocus append={sats} /> +
notify me when ...
Date: Tue, 13 Sep 2022 01:42:09 +0200 Subject: [PATCH 2/8] Implement dynamic coinbase endpoint --- components/job-form.js | 7 +++++-- components/price.js | 22 +++++++++++++++------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/components/job-form.js b/components/job-form.js index 12c2d99a..ca8f4ba2 100644 --- a/components/job-form.js +++ b/components/job-form.js @@ -9,7 +9,7 @@ import styles from '../styles/post.module.css' import { useLazyQuery, gql, useMutation } from '@apollo/client' import { useRouter } from 'next/router' import Link from 'next/link' -import { usePrice } from './price' +import { CURRENCY_SYMBOLS, usePrice } from './price' import Avatar from './avatar' Yup.addMethod(Yup.string, 'or', function (schemas, msg) { @@ -34,13 +34,16 @@ function satsMin2Mo (minute) { function PriceHint ({ monthly }) { const price = usePrice() + const { fiatCurrency } = useMe(); + const fiatSymbol = CURRENCY_SYMBOLS[fiatCurrency] + if (!price) { return null } const fixed = (n, f) => Number.parseFloat(n).toFixed(f) const fiat = fixed((price / 100000000) * monthly, 0) - return {monthly} sats/mo which is ${fiat}/mo + return {monthly} sats/mo which is {fiatSymbol}{fiat}/mo } // need to recent list items diff --git a/components/price.js b/components/price.js index 34350d64..257c12eb 100644 --- a/components/price.js +++ b/components/price.js @@ -2,6 +2,7 @@ import React, { useContext, useEffect, useState } from 'react' import { Button } from 'react-bootstrap' import useSWR from 'swr' import { fixedDecimal } from '../lib/format' +import { useMe } from './me' const fetcher = url => fetch(url).then(res => res.json()).catch() @@ -9,16 +10,22 @@ export const PriceContext = React.createContext({ price: null }) -const ENDPOINT = 'https://api.coinbase.com/v2/prices/BTC-USD/spot' +export const CURRENCY_SYMBOLS = { + 'USD': '$', + 'EUR': '€' +} -export async function getPrice () { - const data = await fetcher(ENDPOINT) +const endpoint = (fiat) => `https://api.coinbase.com/v2/prices/BTC-${fiat}/spot` + +export async function getPrice (fiat) { + const data = await fetcher(endpoint(fiat)) return data?.data?.amount } export function PriceProvider ({ price, children }) { + const { fiatCurrency } = useMe() const { data } = useSWR( - ENDPOINT, + endpoint(fiatCurrency), fetcher, { refreshInterval: 30000 @@ -45,8 +52,9 @@ export default function Price () { useEffect(() => { setAsSats(localStorage.getItem('asSats')) }, []) - const price = usePrice() + const { fiatCurrency } = useMe() + const fiatSymbol = CURRENCY_SYMBOLS[fiatCurrency]; if (!price) return null @@ -66,7 +74,7 @@ export default function Price () { if (asSats === 'yep') { return ( ) } @@ -81,7 +89,7 @@ export default function Price () { return ( ) } From 455ca25efa7d6a9ed022e23689f2fc0a8c878bca Mon Sep 17 00:00:00 2001 From: ekzyis Date: Tue, 13 Sep 2022 01:45:37 +0200 Subject: [PATCH 3/8] Validate currency input --- pages/settings.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pages/settings.js b/pages/settings.js index 100bd4d1..5d8a67b8 100644 --- a/pages/settings.js +++ b/pages/settings.js @@ -12,12 +12,16 @@ import { LightningAuth } from '../components/lightning-auth' import { SETTINGS, SET_SETTINGS } from '../fragments/users' import { useRouter } from 'next/router' import Info from '../components/info' +import { CURRENCY_SYMBOLS } from '../components/price' export const getServerSideProps = getGetServerSideProps(SETTINGS) +const supportedCurrencies = Object.keys(CURRENCY_SYMBOLS) + export const SettingsSchema = Yup.object({ tipDefault: Yup.number().typeError('must be a number').required('required') - .positive('must be positive').integer('must be whole') + .positive('must be positive').integer('must be whole'), + fiatCurrency: Yup.string().required('required').oneOf(supportedCurrencies) }) const warningMessage = 'If I logout, even accidentally, I will never be able to access my account again' From f66a8162da77b01f6bd06e317505978d28a85d29 Mon Sep 17 00:00:00 2001 From: ekzyis Date: Tue, 13 Sep 2022 02:08:24 +0200 Subject: [PATCH 4/8] Fix rebase --- api/ssrApollo.js | 2 +- fragments/users.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/ssrApollo.js b/api/ssrApollo.js index 3335cde1..3e655938 100644 --- a/api/ssrApollo.js +++ b/api/ssrApollo.js @@ -43,7 +43,7 @@ export function getGetServerSideProps (query, variables = null, notFoundFunc, re query: ME_SSR }) - const price = await getPrice() + const price = await getPrice(me.fiatCurrency) // we want to use client-side cache if (nodata && query) { diff --git a/fragments/users.js b/fragments/users.js index 60b9f89e..1816322c 100644 --- a/fragments/users.js +++ b/fragments/users.js @@ -87,10 +87,10 @@ ${SETTINGS_FIELDS} export const SET_SETTINGS = gql` ${SETTINGS_FIELDS} -mutation setSettings($tipDefault: Int!, $noteItemSats: Boolean!, $noteEarning: Boolean!, +mutation setSettings($tipDefault: Int!, $fiatCurrency: String!, $noteItemSats: Boolean!, $noteEarning: Boolean!, $noteAllDescendants: Boolean!, $noteMentions: Boolean!, $noteDeposits: Boolean!, $noteInvites: Boolean!, $noteJobIndicator: Boolean!, $hideInvoiceDesc: Boolean!) { - setSettings(tipDefault: $tipDefault, noteItemSats: $noteItemSats, + setSettings(tipDefault: $tipDefault, fiatCurrency: $fiatCurrency, noteItemSats: $noteItemSats, noteEarning: $noteEarning, noteAllDescendants: $noteAllDescendants, noteMentions: $noteMentions, noteDeposits: $noteDeposits, noteInvites: $noteInvites, noteJobIndicator: $noteJobIndicator, hideInvoiceDesc: $hideInvoiceDesc) { From 7d49b686aab94ad3580ccd77b2e190fabf1faf82 Mon Sep 17 00:00:00 2001 From: ekzyis Date: Tue, 13 Sep 2022 02:24:31 +0200 Subject: [PATCH 5/8] Fix fiatCurrency gql type --- api/typeDefs/user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/typeDefs/user.js b/api/typeDefs/user.js index f1250204..15825a01 100644 --- a/api/typeDefs/user.js +++ b/api/typeDefs/user.js @@ -58,7 +58,7 @@ export default gql` hasNewNotes: Boolean! hasInvites: Boolean! tipDefault: Int! - fiatCurrency: String + fiatCurrency: String! bio: Item bioId: Int photoId: Int From 22e07a4318b2637db0e948a433b58b68633120f5 Mon Sep 17 00:00:00 2001 From: ekzyis Date: Sun, 18 Sep 2022 03:07:14 +0200 Subject: [PATCH 6/8] Fix errors if me null --- api/ssrApollo.js | 2 +- components/price.js | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/api/ssrApollo.js b/api/ssrApollo.js index 3e655938..3c3097c6 100644 --- a/api/ssrApollo.js +++ b/api/ssrApollo.js @@ -43,7 +43,7 @@ export function getGetServerSideProps (query, variables = null, notFoundFunc, re query: ME_SSR }) - const price = await getPrice(me.fiatCurrency) + const price = await getPrice(me?.fiatCurrency) // we want to use client-side cache if (nodata && query) { diff --git a/components/price.js b/components/price.js index 257c12eb..e9573203 100644 --- a/components/price.js +++ b/components/price.js @@ -15,7 +15,7 @@ export const CURRENCY_SYMBOLS = { 'EUR': '€' } -const endpoint = (fiat) => `https://api.coinbase.com/v2/prices/BTC-${fiat}/spot` +const endpoint = (fiat) => `https://api.coinbase.com/v2/prices/BTC-${fiat ?? 'USD'}/spot` export async function getPrice (fiat) { const data = await fetcher(endpoint(fiat)) @@ -23,9 +23,9 @@ export async function getPrice (fiat) { } export function PriceProvider ({ price, children }) { - const { fiatCurrency } = useMe() + const me = useMe() const { data } = useSWR( - endpoint(fiatCurrency), + endpoint(me?.fiatCurrency), fetcher, { refreshInterval: 30000 @@ -53,8 +53,8 @@ export default function Price () { setAsSats(localStorage.getItem('asSats')) }, []) const price = usePrice() - const { fiatCurrency } = useMe() - const fiatSymbol = CURRENCY_SYMBOLS[fiatCurrency]; + const me = useMe() + const fiatSymbol = CURRENCY_SYMBOLS[me?.fiatCurrency || 'USD']; if (!price) return null From c184faf01765e3e8c1301886c651e9be956349a8 Mon Sep 17 00:00:00 2001 From: ekzyis Date: Sun, 18 Sep 2022 03:45:21 +0200 Subject: [PATCH 7/8] Use dropdown for fiat selection in settings --- components/form.js | 32 +++++++++++++++++++++++++------- pages/settings.js | 6 ++++-- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/components/form.js b/components/form.js index e2a2a322..233c28ad 100644 --- a/components/form.js +++ b/components/form.js @@ -6,7 +6,7 @@ import { Formik, Form as FormikForm, useFormikContext, useField, FieldArray } fr import React, { useEffect, useRef, useState } from 'react' import copy from 'clipboard-copy' import Thumb from '../svgs/thumb-up-fill.svg' -import { Col, Dropdown, Nav } from 'react-bootstrap' +import { Col, Dropdown as BootstrapDropdown, Nav } from 'react-bootstrap' import Markdown from '../svgs/markdown-line.svg' import styles from './form.module.css' import Text from '../components/text' @@ -269,10 +269,10 @@ export function InputUserSuggest ({ label, groupClassName, ...props }) { } }} /> - 0}> - + 0}> + {suggestions.array.map((v, i) => - { @@ -281,9 +281,9 @@ export function InputUserSuggest ({ label, groupClassName, ...props }) { }} > {v.name} - )} - - + )} + + ) } @@ -429,3 +429,21 @@ export function SyncForm ({ ) } + +export function Dropdown ({ label, items, groupClassName, ...props }) { + const [field, _, helper] = useField({ ...props, type: 'input' }) + return ( + + + + {field.value} + + + {items.map(item => ( + helper.setValue(item)}>{item} + ))} + + + + ) +} \ No newline at end of file diff --git a/pages/settings.js b/pages/settings.js index 5d8a67b8..993fc8ee 100644 --- a/pages/settings.js +++ b/pages/settings.js @@ -1,4 +1,4 @@ -import { Checkbox, Form, Input, SubmitButton } from '../components/form' +import { Checkbox, Form, Input, SubmitButton, Dropdown } from '../components/form' import * as Yup from 'yup' import { Alert, Button, InputGroup, Modal } from 'react-bootstrap' import LayoutCenter from '../components/layout-center' @@ -82,9 +82,11 @@ export default function Settings ({ data: { settings } }) { autoFocus append={sats} /> -
notify me when ...
Date: Sun, 18 Sep 2022 03:54:13 +0200 Subject: [PATCH 8/8] Add AUD, CAD, GBP, NZD --- components/price.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/price.js b/components/price.js index e9573203..4e4fb383 100644 --- a/components/price.js +++ b/components/price.js @@ -11,8 +11,12 @@ export const PriceContext = React.createContext({ }) export const CURRENCY_SYMBOLS = { + 'AUD': '$', + 'CAD': '$', + 'EUR': '€', + 'GBP': '£', 'USD': '$', - 'EUR': '€' + 'NZD': '$' } const endpoint = (fiat) => `https://api.coinbase.com/v2/prices/BTC-${fiat ?? 'USD'}/spot`