Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
c38d14a633 | |||
38bd029687 | |||
f29a2634fd | |||
61a94e5358 | |||
f05f0dc1ea | |||
c9ceed6c0f | |||
|
a241f90269 | ||
|
a486e5a383 | ||
|
8d20678c75 | ||
|
994382f39c | ||
54ab35e78c | |||
|
02a81213a2 | ||
|
8b5b9a6e30 | ||
|
2936d6d53b | ||
|
4b6926b0b9 | ||
990f91c0a6 | |||
|
81d012b0cb | ||
1b960e5f02 | |||
|
4b6db36646 | ||
0b2de940d0 |
@ -110,7 +110,7 @@ export const ModFilter = React.memo(
|
||||
data-bs-toggle='dropdown'
|
||||
type='button'
|
||||
>
|
||||
{filterOptions.wot}
|
||||
Trust: {filterOptions.wot}
|
||||
</button>
|
||||
<div className='dropdown-menu dropdownMainMenu'>
|
||||
{Object.values(WOTFilterOptions).map((item, index) => {
|
||||
@ -125,18 +125,19 @@ export const ModFilter = React.memo(
|
||||
// when logged in user not admin
|
||||
if (
|
||||
item === WOTFilterOptions.None ||
|
||||
item === WOTFilterOptions.Mine_Only
|
||||
item === WOTFilterOptions.Mine_Only ||
|
||||
item === WOTFilterOptions.Exclude
|
||||
) {
|
||||
const isAdmin =
|
||||
const isWoTNpub =
|
||||
userState.user?.npub ===
|
||||
import.meta.env.VITE_REPORTING_NPUB
|
||||
import.meta.env.VITE_SITE_WOT_NPUB
|
||||
|
||||
const isOwnProfile =
|
||||
author &&
|
||||
userState.auth &&
|
||||
userState.user?.pubkey === author
|
||||
|
||||
if (!(isAdmin || isOwnProfile)) return null
|
||||
if (!(isWoTNpub || isOwnProfile)) return null
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -74,7 +74,6 @@ export const NDKContextProvider = ({ children }: { children: ReactNode }) => {
|
||||
useEffect(() => {
|
||||
window.onunhandledrejection = async (event: PromiseRejectionEvent) => {
|
||||
event.preventDefault()
|
||||
console.log(event.reason)
|
||||
if (event.reason?.name === Dexie.errnames.DatabaseClosed) {
|
||||
console.log(
|
||||
'Could not open Dexie DB, probably version change. Deleting old DB and reloading...'
|
||||
@ -245,7 +244,7 @@ export const NDKContextProvider = ({ children }: { children: ReactNode }) => {
|
||||
// Find the user's relays (10s timeout).
|
||||
const relayUrls = await Promise.race([
|
||||
getRelayListForUser(hexKey, ndk),
|
||||
timeout(10000)
|
||||
timeout(3000)
|
||||
])
|
||||
.then((ndkRelayList) => {
|
||||
if (ndkRelayList) return ndkRelayList[userRelaysType]
|
||||
@ -265,7 +264,9 @@ export const NDKContextProvider = ({ children }: { children: ReactNode }) => {
|
||||
.fetchEvents(
|
||||
filter,
|
||||
{ closeOnEose: true, cacheUsage: NDKSubscriptionCacheUsage.PARALLEL },
|
||||
NDKRelaySet.fromRelayUrls(relayUrls, ndk, true)
|
||||
relayUrls.length
|
||||
? NDKRelaySet.fromRelayUrls(relayUrls, ndk, true)
|
||||
: undefined
|
||||
)
|
||||
.then((ndkEventSet) => {
|
||||
const ndkEvents = Array.from(ndkEventSet)
|
||||
|
@ -66,7 +66,9 @@ export const useComments = (
|
||||
closeOnEose: false,
|
||||
cacheUsage: NDKSubscriptionCacheUsage.CACHE_FIRST
|
||||
},
|
||||
NDKRelaySet.fromRelayUrls(Array.from(relayUrls), ndk)
|
||||
relayUrls.size
|
||||
? NDKRelaySet.fromRelayUrls(Array.from(relayUrls), ndk)
|
||||
: undefined
|
||||
)
|
||||
|
||||
subscription.on('event', (ndkEvent) => {
|
||||
|
@ -54,18 +54,35 @@ export const useFilteredMods = (
|
||||
}
|
||||
|
||||
const wotFilter = (mods: ModDetails[]) => {
|
||||
// Determine the filtering logic based on the WOT filter option
|
||||
// Determine the filtering logic based on the WOT filter option and user state
|
||||
// when user is not logged in use Site_Only
|
||||
if (!userState.auth) {
|
||||
return mods.filter((mod) => isInWoT(siteWot, siteWotLevel, mod.author))
|
||||
}
|
||||
// when user is logged, allow other filter selections
|
||||
const isWoTNpub =
|
||||
userState.user?.npub === import.meta.env.VITE_SITE_WOT_NPUB
|
||||
switch (filterOptions.wot) {
|
||||
case WOTFilterOptions.None:
|
||||
return mods
|
||||
// Only admins can choose None, use siteWoT for others
|
||||
return isWoTNpub
|
||||
? mods
|
||||
: mods.filter((mod) => isInWoT(siteWot, siteWotLevel, mod.author))
|
||||
case WOTFilterOptions.Exclude:
|
||||
// Only admins can choose Exlude, use siteWot for others
|
||||
// Exlude returns the mods not in the site's WoT
|
||||
return isWoTNpub
|
||||
? mods.filter((mod) => !isInWoT(siteWot, siteWotLevel, mod.author))
|
||||
: mods.filter((mod) => isInWoT(siteWot, siteWotLevel, mod.author))
|
||||
case WOTFilterOptions.Site_Only:
|
||||
return mods.filter((mod) =>
|
||||
isInWoT(siteWot, siteWotLevel, mod.author)
|
||||
)
|
||||
case WOTFilterOptions.Mine_Only:
|
||||
return mods.filter((mod) =>
|
||||
isInWoT(userWot, userWotLevel, mod.author)
|
||||
)
|
||||
// Only admins can choose Mine_Only, use siteWoT for others
|
||||
return isWoTNpub
|
||||
? mods.filter((mod) => isInWoT(userWot, userWotLevel, mod.author))
|
||||
: mods.filter((mod) => isInWoT(siteWot, siteWotLevel, mod.author))
|
||||
case WOTFilterOptions.Site_And_Mine:
|
||||
return mods.filter(
|
||||
(mod) =>
|
||||
@ -112,6 +129,7 @@ export const useFilteredMods = (
|
||||
|
||||
return filtered
|
||||
}, [
|
||||
userState.auth,
|
||||
userState.user?.npub,
|
||||
filterOptions.sort,
|
||||
filterOptions.moderated,
|
||||
|
@ -24,9 +24,7 @@ export const Layout = () => {
|
||||
const dispatch = useAppDispatch()
|
||||
const { ndk, fetchEventFromUserRelays } = useNDKContext()
|
||||
const userState = useAppSelector((state) => state.user)
|
||||
const { siteWotStatus, siteWotLevel, userWotLevel } = useAppSelector(
|
||||
(state) => state.wot
|
||||
)
|
||||
const { siteWotStatus } = useAppSelector((state) => state.wot)
|
||||
|
||||
// calculate site's wot
|
||||
useEffect(() => {
|
||||
@ -46,7 +44,7 @@ export const Layout = () => {
|
||||
})
|
||||
}
|
||||
}
|
||||
}, [ndk, siteWotLevel, dispatch])
|
||||
}, [ndk, dispatch])
|
||||
|
||||
// calculate user's wot
|
||||
useEffect(() => {
|
||||
@ -62,7 +60,7 @@ export const Layout = () => {
|
||||
toast.error('An error occurred in calculating user web-of-trust!')
|
||||
})
|
||||
}
|
||||
}, [ndk, userState.user, userWotLevel, dispatch])
|
||||
}, [ndk, userState.user, dispatch])
|
||||
|
||||
// get site's wot level
|
||||
useEffect(() => {
|
||||
@ -72,7 +70,8 @@ export const Layout = () => {
|
||||
fetchEventFromUserRelays(
|
||||
{
|
||||
kinds: [NDKKind.AppSpecificData],
|
||||
'#d': ['degmods']
|
||||
'#d': ['degmods'],
|
||||
authors: [hexPubkey]
|
||||
},
|
||||
hexPubkey,
|
||||
UserRelaysType.Both
|
||||
@ -94,7 +93,8 @@ export const Layout = () => {
|
||||
fetchEventFromUserRelays(
|
||||
{
|
||||
kinds: [NDKKind.AppSpecificData],
|
||||
'#d': ['degmods']
|
||||
'#d': ['degmods'],
|
||||
authors: [hexPubkey]
|
||||
},
|
||||
hexPubkey,
|
||||
UserRelaysType.Both
|
||||
|
@ -22,7 +22,6 @@ export const ReportPopup = ({ handleClose }: ReportPopupProps) => {
|
||||
useEffect(() => {
|
||||
if (fetcher.data) {
|
||||
const { isSent } = fetcher.data
|
||||
console.log(fetcher.data)
|
||||
if (isSent) {
|
||||
handleClose()
|
||||
}
|
||||
|
@ -922,11 +922,13 @@ const Body = ({
|
||||
<div
|
||||
ref={postBodyRef}
|
||||
className='IBMSMSMBSSPostBody'
|
||||
style={{ maxHeight: '250px', padding: '0 10px' }}
|
||||
style={{ maxHeight: '250px', padding: '10px 18px' }}
|
||||
>
|
||||
<EditorContent editor={editor} />
|
||||
<div ref={viewFullPostBtnRef} className='IBMSMSMBSSPostBodyHide'>
|
||||
<p onClick={viewFullPost}>View</p>
|
||||
<div className='IBMSMSMBSSPostBodyHideText'>
|
||||
<p onClick={viewFullPost}>Read Full</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='IBMSMSMBSSShots'>
|
||||
|
@ -4,9 +4,9 @@ import { useAppDispatch, useAppSelector, useNDKContext } from 'hooks'
|
||||
import { kinds, UnsignedEvent, Event } from 'nostr-tools'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { toast } from 'react-toastify'
|
||||
import { setUserWotLevel } from 'store/reducers/wot'
|
||||
import { setSiteWotLevel, setUserWotLevel } from 'store/reducers/wot'
|
||||
import { UserRelaysType } from 'types'
|
||||
import { log, LogType, now } from 'utils'
|
||||
import { log, LogType, now, npubToHex } from 'utils'
|
||||
|
||||
// todo: use components from Input.tsx
|
||||
export const PreferencesSetting = () => {
|
||||
@ -21,16 +21,17 @@ export const PreferencesSetting = () => {
|
||||
|
||||
useEffect(() => {
|
||||
if (user?.pubkey) {
|
||||
const hexPubkey = user.pubkey as string
|
||||
fetchEventFromUserRelays(
|
||||
{
|
||||
kinds: [NDKKind.AppSpecificData],
|
||||
'#d': ['degmods']
|
||||
'#d': ['degmods'],
|
||||
authors: [hexPubkey]
|
||||
},
|
||||
user.pubkey as string,
|
||||
hexPubkey,
|
||||
UserRelaysType.Both
|
||||
).then((event) => {
|
||||
if (event) {
|
||||
console.log('event :>> ', event)
|
||||
const wot = event.tagValue('wot')
|
||||
if (wot) setWotLevel(parseInt(wot))
|
||||
}
|
||||
@ -90,6 +91,13 @@ export const PreferencesSetting = () => {
|
||||
)
|
||||
|
||||
dispatch(setUserWotLevel(wotLevel))
|
||||
|
||||
// If wot admin, update site wot level too
|
||||
const SITE_WOT_NPUB = import.meta.env.VITE_SITE_WOT_NPUB
|
||||
const siteWotPubkey = npubToHex(SITE_WOT_NPUB)
|
||||
if (siteWotPubkey === hexPubkey) {
|
||||
dispatch(setSiteWotLevel(wotLevel))
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
@ -119,6 +127,7 @@ export const PreferencesSetting = () => {
|
||||
className='CheckboxMain'
|
||||
name='notificationsSettings'
|
||||
checked
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
<div className='inputLabelWrapperMain inputLabelWrapperMainAlt inputLabelWrapperMainAltStylized'>
|
||||
@ -130,6 +139,7 @@ export const PreferencesSetting = () => {
|
||||
className='CheckboxMain'
|
||||
name='notificationsSettings'
|
||||
checked
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
<div className='inputLabelWrapperMain inputLabelWrapperMainAlt inputLabelWrapperMainAltStylized'>
|
||||
@ -141,6 +151,7 @@ export const PreferencesSetting = () => {
|
||||
className='CheckboxMain'
|
||||
name='notificationsSettings'
|
||||
checked
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
<div className='inputLabelWrapperMain inputLabelWrapperMainAlt inputLabelWrapperMainAltStylized'>
|
||||
@ -152,6 +163,7 @@ export const PreferencesSetting = () => {
|
||||
className='CheckboxMain'
|
||||
name='notificationsSettings'
|
||||
checked
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
<div className='inputLabelWrapperMain inputLabelWrapperMainAlt inputLabelWrapperMainAltStylized'>
|
||||
@ -163,6 +175,7 @@ export const PreferencesSetting = () => {
|
||||
className='CheckboxMain'
|
||||
name='notificationsSettings'
|
||||
checked
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -212,6 +225,7 @@ export const PreferencesSetting = () => {
|
||||
className='CheckboxMain'
|
||||
name='WoTZap'
|
||||
checked
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -11,7 +11,7 @@ import { Event, kinds, UnsignedEvent } from 'nostr-tools'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { toast } from 'react-toastify'
|
||||
import { UserRelaysType } from 'types'
|
||||
import { log, LogType, normalizeWebSocketURL, now } from 'utils'
|
||||
import { log, LogType, normalizeWebSocketURL, now, timeout } from 'utils'
|
||||
|
||||
const READ_MARKER = 'read'
|
||||
const WRITE_MARKER = 'write'
|
||||
@ -21,12 +21,16 @@ export const RelaySettings = () => {
|
||||
const userState = useAppSelector((state) => state.user)
|
||||
const [ndkRelayList, setNDKRelayList] = useState<NDKRelayList | null>(null)
|
||||
const [isPublishing, setIsPublishing] = useState(false)
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
const [inputValue, setInputValue] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
if (userState.auth && userState.user?.pubkey) {
|
||||
getRelayListForUser(userState.user.pubkey as string, ndk)
|
||||
setIsLoading(true)
|
||||
Promise.race([
|
||||
getRelayListForUser(userState.user?.pubkey as string, ndk),
|
||||
timeout(10000)
|
||||
])
|
||||
.then((res) => {
|
||||
setNDKRelayList(res)
|
||||
})
|
||||
@ -36,9 +40,13 @@ export const RelaySettings = () => {
|
||||
err.message || err
|
||||
}`
|
||||
)
|
||||
setNDKRelayList(null)
|
||||
setNDKRelayList(new NDKRelayList(ndk))
|
||||
})
|
||||
.finally(() => {
|
||||
setIsLoading(false)
|
||||
})
|
||||
} else {
|
||||
setIsLoading(false)
|
||||
setNDKRelayList(null)
|
||||
}
|
||||
}, [userState, ndk])
|
||||
@ -224,6 +232,14 @@ export const RelaySettings = () => {
|
||||
setIsPublishing(false)
|
||||
}
|
||||
|
||||
if (isLoading)
|
||||
return (
|
||||
<>
|
||||
<div></div>
|
||||
<LoadingSpinner desc='Loading' />
|
||||
</>
|
||||
)
|
||||
|
||||
if (!ndkRelayList)
|
||||
return <div>Could not fetch user relay list or user is not logged in </div>
|
||||
|
||||
@ -258,6 +274,12 @@ export const RelaySettings = () => {
|
||||
<div className='inputLabelWrapperMain'>
|
||||
<label className='form-label labelMain'>Your relays</label>
|
||||
</div>
|
||||
{relayEntries.length === 0 && (
|
||||
<>
|
||||
We recommend adding one of our relays if you're planning to
|
||||
frequently use DEG Mods, for a better experience.
|
||||
</>
|
||||
)}
|
||||
{relayEntries.map(([relayUrl, relayType]) => (
|
||||
<RelayListItem
|
||||
key={relayUrl}
|
||||
|
@ -163,11 +163,21 @@
|
||||
flex-direction: column;
|
||||
justify-content: end;
|
||||
align-items: center;
|
||||
padding: 15px;
|
||||
color: rgba(255,255,255,0.75);
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
box-shadow: inset 0 0 8px 0 rgb(0,0,0,0.1);
|
||||
overflow: hidden;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
.IBMSMSMBSSPostBodyHideText {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: rgb(55 55 55);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.IBMSMSMBSSModFor {
|
||||
@ -242,7 +252,7 @@
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.IBMSMSMBSSPostBody > div > div > p {
|
||||
.IBMSMSMBSSPostBody > div:first-child > div > p {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
@ -251,4 +261,31 @@
|
||||
border-bottom: solid 1px rgb(255 255 255 / 10%);
|
||||
padding: 0px 0 10px 0;
|
||||
line-height: 1.5 !important;
|
||||
}
|
||||
|
||||
.dropdown.dropdownMain.dropdownMainBlogpost {
|
||||
flex-grow: unset;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background: rgba(0,0,0,0.1);
|
||||
border-radius: 6px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.IBMSMSMBSSWarning {
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
padding: 10px 15px;
|
||||
border: solid 2px tomato;
|
||||
background: rgba(255,80,80,0.15);
|
||||
color: rgba(255,255,255,0.95);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.IBMSMSMBSSPostBodyHideText > * {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
}
|
@ -21,7 +21,8 @@ export enum WOTFilterOptions {
|
||||
Site_And_Mine = 'Site & Mine',
|
||||
Site_Only = 'Site Only',
|
||||
Mine_Only = 'Mine Only',
|
||||
None = 'None'
|
||||
None = 'None',
|
||||
Exclude = 'Exclude'
|
||||
}
|
||||
|
||||
export interface FilterOptions {
|
||||
|
@ -98,9 +98,7 @@ export const findFollowsAndMuteUsers = async (
|
||||
follows.add(f)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
events.forEach((event) => {
|
||||
if (event.kind === NDKKind.MuteList) {
|
||||
filterValidPTags(event.tags).forEach((f) => {
|
||||
muted.add(f)
|
||||
|
Loading…
Reference in New Issue
Block a user