better organize user graphql types

This commit is contained in:
keyan 2023-11-09 19:05:35 -06:00
parent d86d8b3bac
commit 494b8b3dcd
13 changed files with 372 additions and 291 deletions

View File

@ -23,6 +23,15 @@ const loadContributors = async (set) => {
}
async function authMethods (user, args, { models, me }) {
if (!me || me.id !== user.id) {
return {
lightning: false,
twitter: false,
github: false,
nostr: false
}
}
const accounts = await models.account.findMany({
where: {
userId: me.id
@ -465,7 +474,7 @@ export default {
throw error
}
},
setSettings: async (parent, { nostrRelays, ...data }, { me, models }) => {
setSettings: async (parent, { settings: { nostrRelays, ...data } }, { me, models }) => {
if (!me) {
throw new GraphQLError('you must be logged in', { extensions: { code: 'UNAUTHENTICATED' } })
}
@ -617,7 +626,59 @@ export default {
},
User: {
authMethods,
privates: async (user, args, { me, models }) => {
if (!me || me.id !== user.id) {
return null
}
return user
},
optional: user => user,
meSubscriptionPosts: async (user, args, { me, models }) => {
if (!me) return false
if (typeof user.meSubscriptionPosts !== 'undefined') return user.meSubscriptionPosts
const subscription = await models.userSubscription.findUnique({
where: {
followerId_followeeId: {
followerId: Number(me.id),
followeeId: Number(user.id)
}
}
})
return !!subscription?.postsSubscribedAt
},
meSubscriptionComments: async (user, args, { me, models }) => {
if (!me) return false
if (typeof user.meSubscriptionComments !== 'undefined') return user.meSubscriptionComments
const subscription = await models.userSubscription.findUnique({
where: {
followerId_followeeId: {
followerId: Number(me.id),
followeeId: Number(user.id)
}
}
})
return !!subscription?.commentsSubscribedAt
},
meMute: async (user, args, { me, models }) => {
if (!me) return false
if (typeof user.meMute !== 'undefined') return user.meMute
const mute = await models.mute.findUnique({
where: {
muterId_mutedId: {
muterId: Number(me.id),
mutedId: Number(user.id)
}
}
})
return !!mute
},
since: async (user, args, { models }) => {
// get the user's first item
const item = await models.item.findFirst({
@ -630,12 +691,6 @@ export default {
})
return item?.id
},
maxStreak: async (user, args, { models }) => {
const [{ max }] = await models.$queryRaw`
SELECT MAX(COALESCE("endedAt", (now() AT TIME ZONE 'America/Chicago')::date) - "startedAt")
FROM "Streak" WHERE "userId" = ${user.id}`
return max
},
nitems: async (user, { when, from, to }, { models }) => {
if (typeof user.nitems !== 'undefined') {
return user.nitems
@ -652,21 +707,6 @@ export default {
}
})
},
meMute: async (user, args, { me, models }) => {
if (!me) return false
if (typeof user.meMute !== 'undefined') return user.meMute
const mute = await models.mute.findUnique({
where: {
muterId_mutedId: {
muterId: Number(me.id),
mutedId: Number(user.id)
}
}
})
return !!mute
},
nposts: async (user, { when, from, to }, { models }) => {
if (typeof user.nposts !== 'undefined') {
return user.nposts
@ -701,23 +741,72 @@ export default {
}
})
},
nbookmarks: async (user, { when, from, to }, { models }) => {
if (typeof user.nBookmarks !== 'undefined') {
return user.nBookmarks
bio: async (user, args, { models, me }) => {
return getItem(user, { id: user.bioId }, { models, me })
}
},
UserPrivates: {
sats: async (user, args, { models, me }) => {
if (!me || me.id !== user.id) {
return 0
}
return msatsToSats(user.msats)
},
authMethods,
hasInvites: async (user, args, { models }) => {
const invites = await models.user.findUnique({
where: { id: user.id }
}).invites({ take: 1 })
return invites.length > 0
},
nostrRelays: async (user, args, { models, me }) => {
if (user.id !== me.id) {
return []
}
const [gte, lte] = whenRange(when, from, to)
return await models.bookmark.count({
where: {
userId: user.id,
createdAt: {
gte,
lte
}
}
const relays = await models.userNostrRelay.findMany({
where: { userId: user.id }
})
return relays?.map(r => r.nostrRelayAddr)
}
},
stacked: async (user, { when, from, to }, { models }) => {
UserOptional: {
streak: async (user, args, { models }) => {
if (user.hideCowboyHat) {
return null
}
return user.streak
},
maxStreak: async (user, args, { models }) => {
if (user.hideCowboyHat) {
return null
}
const [{ max }] = await models.$queryRaw`
SELECT MAX(COALESCE("endedAt", (now() AT TIME ZONE 'America/Chicago')::date) - "startedAt")
FROM "Streak" WHERE "userId" = ${user.id}`
return max
},
isContributor: async (user, args, { me }) => {
// lazy init contributors only once
if (contributors.size === 0) {
await loadContributors(contributors)
}
if (me?.id === user.id) {
return contributors.has(user.name)
}
return !user.hideIsContributor && contributors.has(user.name)
},
stacked: async (user, { when, from, to }, { models, me }) => {
if ((!me || me.id !== user.id) && user.hideFromTopUsers) {
return null
}
if (typeof user.stacked !== 'undefined') {
return user.stacked
}
@ -750,7 +839,11 @@ export default {
return 0
},
spent: async (user, { when, from, to }, { models }) => {
spent: async (user, { when, from, to }, { models, me }) => {
if ((!me || me.id !== user.id) && user.hideFromTopUsers) {
return null
}
if (typeof user.spent !== 'undefined') {
return user.spent
}
@ -771,7 +864,11 @@ export default {
return (msats && msatsToSats(msats)) || 0
},
referrals: async (user, { when, from, to }, { models }) => {
referrals: async (user, { when, from, to }, { models, me }) => {
if ((!me || me.id !== user.id) && user.hideFromTopUsers) {
return null
}
if (typeof user.referrals !== 'undefined') {
return user.referrals
}
@ -786,69 +883,6 @@ export default {
}
}
})
},
sats: async (user, args, { models, me }) => {
if (me?.id !== user.id) {
return 0
}
return msatsToSats(user.msats)
},
bio: async (user, args, { models, me }) => {
return getItem(user, { id: user.bioId }, { models, me })
},
hasInvites: async (user, args, { models }) => {
const invites = await models.user.findUnique({
where: { id: user.id }
}).invites({ take: 1 })
return invites.length > 0
},
nostrRelays: async (user, args, { models }) => {
const relays = await models.userNostrRelay.findMany({
where: { userId: user.id }
})
return relays?.map(r => r.nostrRelayAddr)
},
meSubscriptionPosts: async (user, args, { me, models }) => {
if (!me) return false
if (typeof user.meSubscriptionPosts !== 'undefined') return user.meSubscriptionPosts
const subscription = await models.userSubscription.findUnique({
where: {
followerId_followeeId: {
followerId: Number(me.id),
followeeId: Number(user.id)
}
}
})
return !!subscription?.postsSubscribedAt
},
meSubscriptionComments: async (user, args, { me, models }) => {
if (!me) return false
if (typeof user.meSubscriptionComments !== 'undefined') return user.meSubscriptionComments
const subscription = await models.userSubscription.findUnique({
where: {
followerId_followeeId: {
followerId: Number(me.id),
followeeId: Number(user.id)
}
}
})
return !!subscription?.commentsSubscribedAt
},
isContributor: async (user, args, { me }) => {
// lazy init contributors only once
if (contributors.size === 0) {
await loadContributors(contributors)
}
if (me?.id === user.id) {
return contributors.has(user.name)
}
return !user.hideIsContributor && contributors.has(user.name)
}
}
}

View File

@ -87,7 +87,7 @@ export function getGetServerSideProps (
}
const { data: { price } } = await client.query({
query: PRICE, variables: { fiatCurrency: me?.fiatCurrency }
query: PRICE, variables: { fiatCurrency: me?.privates?.fiatCurrency }
})
const { data: { blockHeight } } = await client.query({

View File

@ -20,12 +20,7 @@ export default gql`
extend type Mutation {
setName(name: String!): String
setSettings(tipDefault: Int!, turboTipping: Boolean!, fiatCurrency: String!, withdrawMaxFeeDefault: Int!, noteItemSats: Boolean!,
noteEarning: Boolean!, noteAllDescendants: Boolean!, noteMentions: Boolean!, noteDeposits: Boolean!,
noteInvites: Boolean!, noteJobIndicator: Boolean!, noteCowboyHat: Boolean!, hideInvoiceDesc: Boolean!, autoDropBolt11s: Boolean!,
hideFromTopUsers: Boolean!, hideCowboyHat: Boolean!, imgproxyOnly: Boolean!,
wildWestMode: Boolean!, greeterMode: Boolean!, nostrPubkey: String, nostrCrossposting: Boolean, nostrRelays: [String!], hideBookmarks: Boolean!,
noteForwardedSats: Boolean!, hideWalletBalance: Boolean!, hideIsContributor: Boolean!, diagnostics: Boolean!): User
setSettings(settings: SettingsInput!): User
setPhoto(photoId: ID!): Int!
upsertBio(bio: String!): User!
setWalkthrough(tipPopover: Boolean, upvotePopover: Boolean): Boolean
@ -37,6 +32,56 @@ export default gql`
toggleMute(id: ID): User
}
type User {
id: ID!
createdAt: Date!
name: String
nitems(when: String, from: String, to: String): Int!
nposts(when: String, from: String, to: String): Int!
ncomments(when: String, from: String, to: String): Int!
bio: Item
bioId: Int
photoId: Int
since: Int
optional: UserOptional!
privates: UserPrivates
meMute: Boolean!
meSubscriptionPosts: Boolean!
meSubscriptionComments: Boolean!
}
input SettingsInput {
autoDropBolt11s: Boolean!
diagnostics: Boolean!
fiatCurrency: String!
greeterMode: Boolean!
hideBookmarks: Boolean!
hideCowboyHat: Boolean!
hideFromTopUsers: Boolean!
hideInvoiceDesc: Boolean!
hideIsContributor: Boolean!
hideWalletBalance: Boolean!
imgproxyOnly: Boolean!
nostrCrossposting: Boolean!
nostrPubkey: String
nostrRelays: [String!]
noteAllDescendants: Boolean!
noteCowboyHat: Boolean!
noteDeposits: Boolean!
noteEarning: Boolean!
noteForwardedSats: Boolean!
noteInvites: Boolean!
noteItemSats: Boolean!
noteJobIndicator: Boolean!
noteMentions: Boolean!
tipDefault: Int!
turboTipping: Boolean!
wildWestMode: Boolean!
withdrawMaxFeeDefault: Int!
}
type AuthMethods {
lightning: Boolean!
nostr: Boolean!
@ -45,74 +90,63 @@ export default gql`
email: String
}
type Image {
id: ID!
createdAt: Date!
updatedAt: Date!
type: String!
size: Int!
width: Int
height: Int
itemId: Int
userId: Int!
}
type UserPrivates {
"""
extremely sensitive
"""
sats: Int!
authMethods: AuthMethods!
type User {
id: ID!
createdAt: Date!
name: String
nitems(when: String, from: String, to: String): Int!
nposts(when: String, from: String, to: String): Int!
ncomments(when: String, from: String, to: String): Int!
nbookmarks(when: String, from: String, to: String): Int!
stacked(when: String, from: String, to: String): Int!
spent(when: String, from: String, to: String): Int!
referrals(when: String, from: String, to: String): Int!
freePosts: Int!
freeComments: Int!
"""
only relevant to user
"""
lastCheckedJobs: String
hideWelcomeBanner: Boolean!
tipPopover: Boolean!
upvotePopover: Boolean!
hasInvites: Boolean!
tipDefault: Int!
turboTipping: Boolean!
"""
mirrors SettingsInput
"""
autoDropBolt11s: Boolean!
diagnostics: Boolean!
fiatCurrency: String!
withdrawMaxFeeDefault: Int!
greeterMode: Boolean!
hideBookmarks: Boolean!
hideCowboyHat: Boolean!
hideFromTopUsers: Boolean!
hideInvoiceDesc: Boolean!
hideIsContributor: Boolean!
hideWalletBalance: Boolean!
imgproxyOnly: Boolean!
nostrCrossposting: Boolean!
nostrPubkey: String
nostrRelays: [String!]
bio: Item
bioId: Int
photoId: Int
noteAllDescendants: Boolean!
noteCowboyHat: Boolean!
noteDeposits: Boolean!
noteEarning: Boolean!
noteForwardedSats: Boolean!
noteInvites: Boolean!
noteItemSats: Boolean!
noteJobIndicator: Boolean!
noteMentions: Boolean!
tipDefault: Int!
turboTipping: Boolean!
wildWestMode: Boolean!
withdrawMaxFeeDefault: Int!
}
type UserOptional {
"""
conditionally private
"""
stacked(when: String, from: String, to: String): Int
spent(when: String, from: String, to: String): Int
referrals(when: String, from: String, to: String): Int
streak: Int
maxStreak: Int
sats: Int!
since: Int
upvotePopover: Boolean!
tipPopover: Boolean!
nostrCrossposting: Boolean!
noteItemSats: Boolean!
noteEarning: Boolean!
noteAllDescendants: Boolean!
noteMentions: Boolean!
noteDeposits: Boolean!
noteInvites: Boolean!
noteJobIndicator: Boolean!
noteCowboyHat: Boolean!
noteForwardedSats: Boolean!
hideInvoiceDesc: Boolean!
autoDropBolt11s: Boolean!
hideFromTopUsers: Boolean!
hideCowboyHat: Boolean!
hideBookmarks: Boolean!
hideWelcomeBanner: Boolean!
hideWalletBalance: Boolean!
diagnostics: Boolean!
imgproxyOnly: Boolean!
wildWestMode: Boolean!
greeterMode: Boolean!
lastCheckedJobs: String
authMethods: AuthMethods!
isContributor: Boolean!
hideIsContributor: Boolean!
meSubscriptionPosts: Boolean!
meSubscriptionComments: Boolean!
meMute: Boolean
isContributor: Boolean
}
`

View File

@ -21,11 +21,11 @@ export default function Hat ({ user, badge, className = 'ms-1', height = 16, wid
)
}
if (user.streak === null || user.hideCowboyHat) {
const streak = user.optional.streak
if (streak === null) {
return null
}
const streak = user.streak
return (
<HatTooltip overlayText={streak
? `${numWithUnits(streak, { abbreviate: false, unitSingular: 'day', unitPlural: 'days' })}`

View File

@ -9,9 +9,12 @@ export const MeContext = React.createContext({
export function MeProvider ({ me, children }) {
const { data } = useQuery(ME, SSR ? {} : { pollInterval: 1000, nextFetchPolicy: 'cache-and-network' })
const futureMe = data?.me || me
const contextValue = {
me: data?.me || me
me: futureMe
? { ...futureMe, ...futureMe.privates, ...futureMe.optional }
: null
}
return (

View File

@ -69,7 +69,7 @@ export default function Seo ({ sub, item, user }) {
}
}
if (user) {
desc = `@${user.name} has [${user.stacked} stacked, ${numWithUnits(user.nitems, { unitSingular: 'item', unitPlural: 'items' })}]`
desc = `@${user.name} has [${user.optional.stacked ? `${user.optional.stacked} stacked,` : ''}${numWithUnits(user.nitems, { unitSingular: 'item', unitPlural: 'items' })}]`
}
return (

View File

@ -187,9 +187,11 @@ function HeaderHeader ({ user }) {
const isMe = me?.name === user.name
const Satistics = () => (
user.optional.stacked !== null &&
<div className={`mb-2 ms-0 ms-sm-1 ${styles.username} text-success`}>
{numWithUnits(user.stacked, { abbreviate: false, format: true })} stacked
</div>)
{numWithUnits(user.optional.stacked, { abbreviate: false, format: true })} stacked
</div>
)
const lnurlp = encodeLNUrl(new URL(`https://stacker.news/.well-known/lnurlp/${user.name}`))
return (
@ -227,8 +229,8 @@ function HeaderHeader ({ user }) {
? <Link href={`/items/${user.since}`} className='ms-1'>#{user.since}</Link>
: <span>never</span>}
</small>
<small className='text-muted d-flex-inline'>longest cowboy streak: {user.maxStreak !== null ? user.maxStreak : 'none'}</small>
{user.isContributor && <small className='text-muted d-flex align-items-center'><CodeIcon className='me-1' height={16} width={16} /> verified stacker.news contributor</small>}
{user.optional.maxStreak !== null && <small className='text-muted d-flex-inline'>longest cowboy streak: {user.optional.maxStreak}</small>}
{user.optional.isContributor && <small className='text-muted d-flex align-items-center'><CodeIcon className='me-1' height={16} width={16} /> verified stacker.news contributor</small>}
</div>
</div>
</div>

View File

@ -10,8 +10,8 @@ import { useData } from './use-data'
import Hat from './hat'
// all of this nonsense is to show the stat we are sorting by first
const Stacked = ({ user }) => (<span>{abbrNum(user.stacked)} stacked</span>)
const Spent = ({ user }) => (<span>{abbrNum(user.spent)} spent</span>)
const Stacked = ({ user }) => (user.optional.stacked !== null && <span>{abbrNum(user.optional.stacked)} stacked</span>)
const Spent = ({ user }) => (user.optional.spent !== null && <span>{abbrNum(user.optional.spent)} spent</span>)
const Posts = ({ user }) => (
<Link href={`/${user.name}/posts`} className='text-reset'>
{numWithUnits(user.nposts, { unitSingular: 'post', unitPlural: 'posts' })}
@ -20,7 +20,7 @@ const Comments = ({ user }) => (
<Link href={`/${user.name}/comments`} className='text-reset'>
{numWithUnits(user.ncomments, { unitSingular: 'comment', unitPlural: 'comments' })}
</Link>)
const Referrals = ({ user }) => (<span>{numWithUnits(user.referrals, { unitSingular: 'referral', unitPlural: 'referrals' })}</span>)
const Referrals = ({ user }) => (user.optional.referrals !== null && <span>{numWithUnits(user.optional.referrals, { unitSingular: 'referral', unitPlural: 'referrals' })}</span>)
const Seperator = () => (<span> \ </span>)
const STAT_POS = {

View File

@ -8,10 +8,11 @@ export const COMMENT_FIELDS = gql`
deletedAt
text
user {
name
streak
hideCowboyHat
id
name
optional {
streak
}
meMute
}
sats
@ -45,8 +46,9 @@ export const COMMENTS_ITEM_EXT_FIELDS = gql`
subName
user {
name
optional {
streak
hideCowboyHat
}
id
}
}

View File

@ -5,17 +5,18 @@ export const INVITE_FIELDS = gql`
id
createdAt
invitees {
name
id
name
}
gift
limit
revoked
user {
name
streak
hideCowboyHat
id
name
optional {
streak
}
}
poor
}

View File

@ -10,10 +10,11 @@ export const ITEM_FIELDS = gql`
title
url
user {
name
streak
hideCowboyHat
id
name
optional {
streak
}
meMute
}
otsHash
@ -60,10 +61,11 @@ export const ITEM_FULL_FIELDS = gql`
bountyPaidTo
subName
user {
name
streak
hideCowboyHat
id
name
optional {
streak
}
}
}
forwards {

View File

@ -7,46 +7,49 @@ export const ME = gql`
me {
id
name
streak
sats
stacked
freePosts
freeComments
tipDefault
turboTipping
fiatCurrency
withdrawMaxFeeDefault
bioId
upvotePopover
tipPopover
nostrCrossposting
noteItemSats
noteEarning
noteAllDescendants
noteMentions
noteDeposits
noteInvites
noteJobIndicator
noteCowboyHat
noteForwardedSats
hideInvoiceDesc
privates {
autoDropBolt11s
hideFromTopUsers
hideCowboyHat
imgproxyOnly
diagnostics
wildWestMode
fiatCurrency
greeterMode
lastCheckedJobs
hideWelcomeBanner
hideWalletBalance
isContributor
hideCowboyHat
hideFromTopUsers
hideInvoiceDesc
hideIsContributor
hideWalletBalance
hideWelcomeBanner
imgproxyOnly
lastCheckedJobs
nostrCrossposting
noteAllDescendants
noteCowboyHat
noteDeposits
noteEarning
noteForwardedSats
noteInvites
noteItemSats
noteJobIndicator
noteMentions
sats
tipDefault
tipPopover
turboTipping
upvotePopover
wildWestMode
withdrawMaxFeeDefault
}
optional {
isContributor
stacked
streak
}
}
}`
export const SETTINGS_FIELDS = gql`
fragment SettingsFields on User {
privates {
tipDefault
turboTipping
fiatCurrency
@ -81,6 +84,7 @@ export const SETTINGS_FIELDS = gql`
twitter
email
}
}
}`
export const SETTINGS = gql`
@ -94,22 +98,11 @@ ${SETTINGS_FIELDS}
export const SET_SETTINGS =
gql`
${SETTINGS_FIELDS}
mutation setSettings($tipDefault: Int!, $turboTipping: Boolean!, $fiatCurrency: String!, $withdrawMaxFeeDefault: Int!, $noteItemSats: Boolean!,
$noteEarning: Boolean!, $noteAllDescendants: Boolean!, $noteMentions: Boolean!, $noteDeposits: Boolean!,
$noteInvites: Boolean!, $noteJobIndicator: Boolean!, $noteCowboyHat: Boolean!, $hideInvoiceDesc: Boolean!, $autoDropBolt11s: Boolean!,
$hideFromTopUsers: Boolean!, $hideCowboyHat: Boolean!, $imgproxyOnly: Boolean!,
$wildWestMode: Boolean!, $greeterMode: Boolean!, $nostrPubkey: String, $nostrCrossposting: Boolean!, $nostrRelays: [String!], $hideBookmarks: Boolean!,
$noteForwardedSats: Boolean!, $hideWalletBalance: Boolean!, $hideIsContributor: Boolean!, $diagnostics: Boolean!) {
setSettings(tipDefault: $tipDefault, turboTipping: $turboTipping, fiatCurrency: $fiatCurrency, withdrawMaxFeeDefault: $withdrawMaxFeeDefault,
noteItemSats: $noteItemSats, noteEarning: $noteEarning, noteAllDescendants: $noteAllDescendants,
noteMentions: $noteMentions, noteDeposits: $noteDeposits, noteInvites: $noteInvites,
noteJobIndicator: $noteJobIndicator, noteCowboyHat: $noteCowboyHat, hideInvoiceDesc: $hideInvoiceDesc, autoDropBolt11s: $autoDropBolt11s,
hideFromTopUsers: $hideFromTopUsers, hideCowboyHat: $hideCowboyHat, imgproxyOnly: $imgproxyOnly,
wildWestMode: $wildWestMode, greeterMode: $greeterMode, nostrPubkey: $nostrPubkey, nostrCrossposting: $nostrCrossposting, nostrRelays: $nostrRelays, hideBookmarks: $hideBookmarks,
noteForwardedSats: $noteForwardedSats, hideWalletBalance: $hideWalletBalance, hideIsContributor: $hideIsContributor, diagnostics: $diagnostics) {
mutation setSettings($settings: SettingsInput!) {
setSettings(settings: $settings) {
...SettingsFields
}
}
}
`
export const NAME_QUERY =
@ -139,32 +132,36 @@ gql`
searchUsers(q: $q, limit: $limit, similarity: $similarity) {
id
name
streak
hideCowboyHat
photoId
stacked
spent
ncomments
nposts
optional {
streak
stacked
spent
referrals
}
}
}`
export const USER_FIELDS = gql`
fragment UserFields on User {
id
name
streak
maxStreak
hideCowboyHat
nitems
stacked
since
photoId
isContributor
nitems
meSubscriptionPosts
meSubscriptionComments
meMute
optional {
stacked
streak
maxStreak
isContributor
}
}`
export const TOP_USERS = gql`
@ -173,15 +170,17 @@ export const TOP_USERS = gql`
users {
id
name
streak
hideCowboyHat
photoId
stacked(when: $when, from: $from, to: $to)
spent(when: $when, from: $from, to: $to)
ncomments(when: $when, from: $from, to: $to)
nposts(when: $when, from: $from, to: $to)
optional {
streak
stacked(when: $when, from: $from, to: $to)
spent(when: $when, from: $from, to: $to)
referrals(when: $when, from: $from, to: $to)
}
}
cursor
}
}
@ -193,15 +192,17 @@ export const TOP_COWBOYS = gql`
users {
id
name
streak
hideCowboyHat
photoId
stacked(when: "forever")
spent(when: "forever")
ncomments(when: "forever")
nposts(when: "forever")
optional {
streak
stacked(when: "forever")
spent(when: "forever")
referrals(when: "forever")
}
}
cursor
}
}

View File

@ -52,7 +52,7 @@ export default function Settings ({ ssrData }) {
const logger = useLogger()
const { data } = useQuery(SETTINGS)
const { settings } = data || ssrData
const { settings: { privates: settings } } = data || ssrData
if (!data && !ssrData) return <PageLoading />
return (
@ -105,12 +105,14 @@ export default function Settings ({ ssrData }) {
try {
await setSettings({
variables: {
settings: {
tipDefault: Number(tipDefault),
withdrawMaxFeeDefault: Number(withdrawMaxFeeDefault),
nostrPubkey,
nostrRelays: nostrRelaysFiltered,
...values
}
}
})
toaster.success('saved settings')
} catch (err) {