seen user db
This commit is contained in:
parent
5cc08aaace
commit
344e309d4e
@ -16,6 +16,8 @@
|
|||||||
"@types/webscopeio__react-textarea-autocomplete": "^4.7.2",
|
"@types/webscopeio__react-textarea-autocomplete": "^4.7.2",
|
||||||
"@webscopeio/react-textarea-autocomplete": "^4.9.2",
|
"@webscopeio/react-textarea-autocomplete": "^4.9.2",
|
||||||
"bech32": "^2.0.0",
|
"bech32": "^2.0.0",
|
||||||
|
"dexie": "^3.2.2",
|
||||||
|
"dexie-react-hooks": "^1.1.1",
|
||||||
"light-bolt11-decoder": "^2.1.0",
|
"light-bolt11-decoder": "^2.1.0",
|
||||||
"qr-code-styling": "^1.6.0-rc.1",
|
"qr-code-styling": "^1.6.0-rc.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
16
src/db.ts
Normal file
16
src/db.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import Dexie, { Table } from 'dexie';
|
||||||
|
|
||||||
|
import type { User } from './nostr/types';
|
||||||
|
|
||||||
|
export class MySubClassedDexie extends Dexie {
|
||||||
|
users!: Table<User>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super('snortDB');
|
||||||
|
this.version(1).stores({
|
||||||
|
users: '++pubkey, name, display_name, about, nip05' // Primary key and indexed props
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const db = new MySubClassedDexie();
|
@ -1,4 +1,5 @@
|
|||||||
import { Component } from "react";
|
import { useSelector } from "react-redux";
|
||||||
|
import { useLiveQuery } from "dexie-react-hooks";
|
||||||
|
|
||||||
import ReactTextareaAutocomplete from "@webscopeio/react-textarea-autocomplete";
|
import ReactTextareaAutocomplete from "@webscopeio/react-textarea-autocomplete";
|
||||||
|
|
||||||
@ -11,10 +12,11 @@ import Nostrich from "../nostrich.jpg";
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
import { hexToBech32 } from "../Util";
|
import { hexToBech32 } from "../Util";
|
||||||
import type { User } from "../nostr/types";
|
import type { User } from "../nostr/types";
|
||||||
|
import { db } from "../db";
|
||||||
|
|
||||||
function searchUsers(query: string, users: Record<string, User>) {
|
function searchUsers(query: string, users: User[]) {
|
||||||
const q = query.toLowerCase()
|
const q = query.toLowerCase()
|
||||||
return Object.values(users).filter(({ name, display_name, about, nip05 }) => {
|
return users.filter(({ name, display_name, about, nip05 }: User) => {
|
||||||
return name?.toLowerCase().includes(q)
|
return name?.toLowerCase().includes(q)
|
||||||
|| display_name?.toLowerCase().includes(q)
|
|| display_name?.toLowerCase().includes(q)
|
||||||
|| about?.toLowerCase().includes(q)
|
|| about?.toLowerCase().includes(q)
|
||||||
@ -37,29 +39,39 @@ const UserItem = ({ pubkey, display_name, picture, nip05, ...rest }: User) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Textarea extends Component {
|
function normalizeUser({ pubkey, about, nip05, name, display_name }: User) {
|
||||||
render() {
|
return { pubkey, about, nip05, name, display_name }
|
||||||
|
}
|
||||||
|
|
||||||
|
const Textarea = ({ onChange, ...rest }: any) => {
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
const { users, onChange, ...rest } = this.props
|
const { users } = useSelector(s => s.users)
|
||||||
|
const dbUsers = useLiveQuery(
|
||||||
|
() => db.users.toArray().then(usrs => {
|
||||||
|
return usrs.reduce((acc, usr) => {
|
||||||
|
return { ...acc, [usr.pubkey]: normalizeUser(usr)}
|
||||||
|
}, {})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
const cachedUsers = dbUsers ? dbUsers : {}
|
||||||
|
const allUsers: User[] = Object.values({...cachedUsers, ...users})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactTextareaAutocomplete
|
<ReactTextareaAutocomplete
|
||||||
{...rest}
|
{...rest}
|
||||||
loadingComponent={() => <span>Loading....</span>}
|
loadingComponent={() => <span>Loading....</span>}
|
||||||
placeholder="Say something!"
|
placeholder="Say something!"
|
||||||
ref={rta => {
|
|
||||||
// @ts-expect-error
|
|
||||||
this.rta = rta;
|
|
||||||
}}
|
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
trigger={{
|
trigger={{
|
||||||
"@": {
|
"@": {
|
||||||
afterWhitespace: true,
|
afterWhitespace: true,
|
||||||
dataProvider: token => searchUsers(token, users),
|
dataProvider: token => dbUsers ? searchUsers(token, allUsers) : [],
|
||||||
component: (props: any) => <UserItem {...props.entity} />,
|
component: (props: any) => <UserItem {...props.entity} />,
|
||||||
output: (item: any) => `@${hexToBech32("npub", item.pubkey)}`
|
output: (item: any) => `@${hexToBech32("npub", item.pubkey)}`
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default Textarea
|
||||||
|
@ -4,6 +4,7 @@ import EventKind from "../nostr/EventKind";
|
|||||||
import { Subscriptions } from "../nostr/Subscriptions";
|
import { Subscriptions } from "../nostr/Subscriptions";
|
||||||
import { addDirectMessage, addNotifications, setFollows, setRelays } from "../state/Login";
|
import { addDirectMessage, addNotifications, setFollows, setRelays } from "../state/Login";
|
||||||
import { setUserData } from "../state/Users";
|
import { setUserData } from "../state/Users";
|
||||||
|
import { db } from "../db";
|
||||||
import useSubscription from "./Subscription";
|
import useSubscription from "./Subscription";
|
||||||
import { mapEventToProfile } from "./UsersFeed";
|
import { mapEventToProfile } from "./UsersFeed";
|
||||||
|
|
||||||
@ -41,7 +42,8 @@ export default function useLoginFeed() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let contactList = notes.filter(a => a.kind === EventKind.ContactList);
|
let contactList = notes.filter(a => a.kind === EventKind.ContactList);
|
||||||
let notifications = notes.filter(a => a.kind === EventKind.TextNote);
|
let notifications = notes.filter(a => a.kind === EventKind.TextNote);
|
||||||
let metadata = notes.filter(a => a.kind === EventKind.SetMetadata).map(a => mapEventToProfile(a));
|
let metadata = notes.filter(a => a.kind === EventKind.SetMetadata)
|
||||||
|
let profiles = metadata.map(a => mapEventToProfile(a));
|
||||||
let dms = notes.filter(a => a.kind === EventKind.DirectMessage);
|
let dms = notes.filter(a => a.kind === EventKind.DirectMessage);
|
||||||
|
|
||||||
for (let cl of contactList) {
|
for (let cl of contactList) {
|
||||||
@ -60,7 +62,11 @@ export default function useLoginFeed() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
dispatch(addNotifications(notifications));
|
dispatch(addNotifications(notifications));
|
||||||
dispatch(setUserData(metadata));
|
dispatch(setUserData(profiles));
|
||||||
|
const userMetadata = metadata.map(ev => {
|
||||||
|
return {...JSON.parse(ev.content), pubkey: ev.pubkey }
|
||||||
|
})
|
||||||
|
db.users.bulkPut(metadata);
|
||||||
dispatch(addDirectMessage(dms));
|
dispatch(addDirectMessage(dms));
|
||||||
}, [notes]);
|
}, [notes]);
|
||||||
}
|
}
|
@ -2,6 +2,7 @@ import { useEffect, useMemo } from "react";
|
|||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { ProfileCacheExpire } from "../Const";
|
import { ProfileCacheExpire } from "../Const";
|
||||||
import EventKind from "../nostr/EventKind";
|
import EventKind from "../nostr/EventKind";
|
||||||
|
import { db } from "../db";
|
||||||
import { Subscriptions } from "../nostr/Subscriptions";
|
import { Subscriptions } from "../nostr/Subscriptions";
|
||||||
import { setUserData } from "../state/Users";
|
import { setUserData } from "../state/Users";
|
||||||
import useSubscription from "./Subscription";
|
import useSubscription from "./Subscription";
|
||||||
@ -34,7 +35,12 @@ export default function useUsersCache() {
|
|||||||
const results = useSubscription(sub);
|
const results = useSubscription(sub);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(setUserData(results.notes.map(a => mapEventToProfile(a))));
|
const userData = results.notes.map(a => mapEventToProfile(a));
|
||||||
|
dispatch(setUserData(userData));
|
||||||
|
const profiles = results.notes.map(ev => {
|
||||||
|
return {...JSON.parse(ev.content), pubkey: ev.pubkey }
|
||||||
|
});
|
||||||
|
db.users.bulkPut(profiles);
|
||||||
}, [results]);
|
}, [results]);
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export type User = {
|
export interface User {
|
||||||
name?: string
|
name?: string
|
||||||
about?: string
|
about?: string
|
||||||
display_name?: string
|
display_name?: string
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { createSlice } from '@reduxjs/toolkit'
|
import { createSlice } from '@reduxjs/toolkit'
|
||||||
import { ProfileCacheExpire } from '../Const';
|
import { ProfileCacheExpire } from '../Const';
|
||||||
|
import { db } from '../db';
|
||||||
|
|
||||||
const UsersSlice = createSlice({
|
const UsersSlice = createSlice({
|
||||||
name: "Users",
|
name: "Users",
|
||||||
@ -67,6 +68,14 @@ const UsersSlice = createSlice({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
state.users[x.pubkey] = x;
|
state.users[x.pubkey] = x;
|
||||||
|
db.users.put({
|
||||||
|
pubkey: x.pubkey,
|
||||||
|
name: x.name,
|
||||||
|
display_name: x.display_name,
|
||||||
|
nip05: x.nip05,
|
||||||
|
picture: x.picture,
|
||||||
|
about: x.about,
|
||||||
|
})
|
||||||
window.localStorage.setItem(`user:${x.pubkey}`, JSON.stringify(x));
|
window.localStorage.setItem(`user:${x.pubkey}`, JSON.stringify(x));
|
||||||
|
|
||||||
state.users = {
|
state.users = {
|
||||||
|
10
yarn.lock
10
yarn.lock
@ -3704,6 +3704,16 @@ detective@^5.2.1:
|
|||||||
defined "^1.0.0"
|
defined "^1.0.0"
|
||||||
minimist "^1.2.6"
|
minimist "^1.2.6"
|
||||||
|
|
||||||
|
dexie-react-hooks@^1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/dexie-react-hooks/-/dexie-react-hooks-1.1.1.tgz#ff405cc89e5d899ddbac5e40d593f83f9a74106a"
|
||||||
|
integrity sha512-Cam5JP6PxHN564RvWEoe8cqLhosW0O4CAZ9XEVYeGHJBa6KEJlOpd9CUpV3kmU9dm2MrW97/lk7qkf1xpij7gA==
|
||||||
|
|
||||||
|
dexie@^3.2.2:
|
||||||
|
version "3.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/dexie/-/dexie-3.2.2.tgz#fa6f2a3c0d6ed0766f8d97a03720056f88fe0e01"
|
||||||
|
integrity sha512-q5dC3HPmir2DERlX+toCBbHQXW5MsyrFqPFcovkH9N2S/UW/H3H5AWAB6iEOExeraAu+j+zRDG+zg/D7YhH0qg==
|
||||||
|
|
||||||
didyoumean@^1.2.2:
|
didyoumean@^1.2.2:
|
||||||
version "1.2.2"
|
version "1.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
|
resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user