mirror of
https://github.com/luminous-devs/lume.git
synced 2024-09-19 11:43:30 +00:00
converted full sql from onboarding flow to prisma
This commit is contained in:
parent
33000979ed
commit
3f87d510ab
2
.gitignore
vendored
2
.gitignore
vendored
@ -15,6 +15,8 @@ out
|
|||||||
.next
|
.next
|
||||||
.vscode
|
.vscode
|
||||||
pnpm-lock.yaml
|
pnpm-lock.yaml
|
||||||
|
*.db
|
||||||
|
*.db-journal
|
||||||
|
|
||||||
# Editor directories and files
|
# Editor directories and files
|
||||||
.vscode/*
|
.vscode/*
|
||||||
|
1
src-tauri/.gitignore
vendored
1
src-tauri/.gitignore
vendored
@ -4,4 +4,3 @@
|
|||||||
|
|
||||||
# prisma
|
# prisma
|
||||||
src/db.rs
|
src/db.rs
|
||||||
lume.db
|
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Account" (
|
||||||
|
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
"pubkey" TEXT NOT NULL,
|
||||||
|
"privkey" TEXT NOT NULL,
|
||||||
|
"active" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"metadata" TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Follow" (
|
||||||
|
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
"pubkey" TEXT NOT NULL,
|
||||||
|
"kind" INTEGER NOT NULL,
|
||||||
|
"metadata" TEXT NOT NULL,
|
||||||
|
"accountId" INTEGER NOT NULL,
|
||||||
|
CONSTRAINT "Follow_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "Account" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Note" (
|
||||||
|
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
"eventId" TEXT NOT NULL,
|
||||||
|
"pubkey" TEXT NOT NULL,
|
||||||
|
"kind" INTEGER NOT NULL,
|
||||||
|
"tags" TEXT NOT NULL,
|
||||||
|
"content" TEXT NOT NULL,
|
||||||
|
"parent_id" TEXT NOT NULL,
|
||||||
|
"parent_comment_id" TEXT NOT NULL,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"accountId" INTEGER NOT NULL,
|
||||||
|
CONSTRAINT "Note_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "Account" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Message" (
|
||||||
|
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
"pubkey" TEXT NOT NULL,
|
||||||
|
"content" TEXT NOT NULL,
|
||||||
|
"tags" TEXT NOT NULL,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"accountId" INTEGER NOT NULL,
|
||||||
|
CONSTRAINT "Message_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "Account" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Relay" (
|
||||||
|
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
"url" TEXT NOT NULL,
|
||||||
|
"active" BOOLEAN NOT NULL DEFAULT true
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Setting" (
|
||||||
|
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
"key" TEXT NOT NULL,
|
||||||
|
"value" TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Account_privkey_key" ON "Account"("privkey");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "Account_pubkey_idx" ON "Account"("pubkey");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Note_eventId_key" ON "Note"("eventId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "Note_eventId_idx" ON "Note"("eventId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "Message_pubkey_idx" ON "Message"("pubkey");
|
3
src-tauri/prisma/migrations/migration_lock.toml
Normal file
3
src-tauri/prisma/migrations/migration_lock.toml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Please do not edit this file manually
|
||||||
|
# It should be added in your version-control system (i.e. Git)
|
||||||
|
provider = "sqlite"
|
@ -1,6 +1,6 @@
|
|||||||
datasource db {
|
datasource db {
|
||||||
provider = "sqlite"
|
provider = "sqlite"
|
||||||
url = "file:../lume.db"
|
url = "file:../../lume.db"
|
||||||
}
|
}
|
||||||
|
|
||||||
generator client {
|
generator client {
|
||||||
@ -37,6 +37,7 @@ model Follow {
|
|||||||
|
|
||||||
model Note {
|
model Note {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
|
eventId String @unique
|
||||||
pubkey String
|
pubkey String
|
||||||
kind Int
|
kind Int
|
||||||
tags String
|
tags String
|
||||||
@ -47,6 +48,8 @@ model Note {
|
|||||||
|
|
||||||
Account Account @relation(fields: [accountId], references: [id])
|
Account Account @relation(fields: [accountId], references: [id])
|
||||||
accountId Int
|
accountId Int
|
||||||
|
|
||||||
|
@@index([eventId])
|
||||||
}
|
}
|
||||||
|
|
||||||
model Message {
|
model Message {
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate objc;
|
extern crate objc;
|
||||||
|
|
||||||
|
use prisma_client_rust::raw;
|
||||||
use tauri::{Manager, WindowEvent};
|
use tauri::{Manager, WindowEvent};
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
use window_ext::WindowExt;
|
use window_ext::WindowExt;
|
||||||
@ -31,6 +32,11 @@ struct CreateAccountData {
|
|||||||
metadata: String,
|
metadata: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Type)]
|
||||||
|
struct GetFollowData {
|
||||||
|
account_id: i32,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Type)]
|
#[derive(Deserialize, Type)]
|
||||||
struct CreateFollowData {
|
struct CreateFollowData {
|
||||||
pubkey: String,
|
pubkey: String,
|
||||||
@ -39,6 +45,18 @@ struct CreateFollowData {
|
|||||||
account_id: i32,
|
account_id: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Type)]
|
||||||
|
struct CreateNoteData {
|
||||||
|
event_id: String,
|
||||||
|
pubkey: String,
|
||||||
|
kind: i32,
|
||||||
|
tags: String,
|
||||||
|
content: String,
|
||||||
|
parent_id: String,
|
||||||
|
parent_comment_id: String,
|
||||||
|
account_id: i32,
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
#[specta::specta]
|
#[specta::specta]
|
||||||
async fn get_account(db: DbState<'_>) -> Result<Vec<account::Data>, ()> {
|
async fn get_account(db: DbState<'_>) -> Result<Vec<account::Data>, ()> {
|
||||||
@ -59,6 +77,16 @@ async fn create_account(db: DbState<'_>, data: CreateAccountData) -> Result<acco
|
|||||||
.map_err(|_| ())
|
.map_err(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
|
async fn get_follows(db: DbState<'_>, data: GetFollowData) -> Result<Vec<follow::Data>, ()> {
|
||||||
|
db.follow()
|
||||||
|
.find_many(vec![follow::account_id::equals(data.account_id)])
|
||||||
|
.exec()
|
||||||
|
.await
|
||||||
|
.map_err(|_| ())
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
#[specta::specta]
|
#[specta::specta]
|
||||||
async fn create_follow(db: DbState<'_>, data: CreateFollowData) -> Result<follow::Data, ()> {
|
async fn create_follow(db: DbState<'_>, data: CreateFollowData) -> Result<follow::Data, ()> {
|
||||||
@ -75,13 +103,68 @@ async fn create_follow(db: DbState<'_>, data: CreateFollowData) -> Result<follow
|
|||||||
.map_err(|_| ())
|
.map_err(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
|
async fn create_note(db: DbState<'_>, data: CreateNoteData) -> Result<note::Data, ()> {
|
||||||
|
let event_id = data.event_id.clone();
|
||||||
|
let content = data.content.clone();
|
||||||
|
|
||||||
|
db.note()
|
||||||
|
.upsert(
|
||||||
|
note::event_id::equals(event_id),
|
||||||
|
note::create(
|
||||||
|
data.event_id,
|
||||||
|
data.pubkey,
|
||||||
|
data.kind,
|
||||||
|
data.tags,
|
||||||
|
data.content,
|
||||||
|
data.parent_id,
|
||||||
|
data.parent_comment_id,
|
||||||
|
account::id::equals(data.account_id),
|
||||||
|
vec![],
|
||||||
|
),
|
||||||
|
vec![note::content::set(content)],
|
||||||
|
)
|
||||||
|
.exec()
|
||||||
|
.await
|
||||||
|
.map_err(|_| ())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
|
async fn get_notes(db: DbState<'_>) -> Result<Vec<note::Data>, ()> {
|
||||||
|
db._query_raw(raw!("SELECT * FROM Note"))
|
||||||
|
.exec()
|
||||||
|
.await
|
||||||
|
.map_err(|_| ())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
|
async fn check_note(db: DbState<'_>) -> Result<Vec<note::Data>, ()> {
|
||||||
|
db.note()
|
||||||
|
.find_many(vec![])
|
||||||
|
.take(5)
|
||||||
|
.exec()
|
||||||
|
.await
|
||||||
|
.map_err(|_| ())
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let db = PrismaClient::_builder().build().await.unwrap();
|
let db = PrismaClient::_builder().build().await.unwrap();
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
ts::export(
|
ts::export(
|
||||||
collect_types![get_account, create_account, create_follow],
|
collect_types![
|
||||||
|
get_account,
|
||||||
|
create_account,
|
||||||
|
get_follows,
|
||||||
|
create_follow,
|
||||||
|
create_note,
|
||||||
|
get_notes,
|
||||||
|
check_note
|
||||||
|
],
|
||||||
"../src/utils/bindings.ts",
|
"../src/utils/bindings.ts",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -115,7 +198,11 @@ async fn main() {
|
|||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
get_account,
|
get_account,
|
||||||
create_account,
|
create_account,
|
||||||
create_follow
|
get_follows,
|
||||||
|
create_follow,
|
||||||
|
create_note,
|
||||||
|
get_notes,
|
||||||
|
check_note
|
||||||
])
|
])
|
||||||
.manage(Arc::new(db))
|
.manage(Arc::new(db))
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { RelayContext } from '@components/relaysProvider';
|
import { RelayContext } from '@components/relaysProvider';
|
||||||
|
|
||||||
import { activeAccountAtom } from '@stores/account';
|
import { activeAccountAtom, lastLoginAtom } from '@stores/account';
|
||||||
import { hasNewerNoteAtom } from '@stores/note';
|
import { hasNewerNoteAtom } from '@stores/note';
|
||||||
|
|
||||||
import { dateToUnix } from '@utils/getDate';
|
import { dateToUnix } from '@utils/getDate';
|
||||||
import { createCacheNote, getAllFollowsByID, updateLastLoginTime } from '@utils/storage';
|
import { createCacheNote, getAllFollowsByID } from '@utils/storage';
|
||||||
import { pubkeyArray } from '@utils/transform';
|
import { pubkeyArray } from '@utils/transform';
|
||||||
|
|
||||||
import { TauriEvent } from '@tauri-apps/api/event';
|
import { TauriEvent } from '@tauri-apps/api/event';
|
||||||
@ -15,6 +15,7 @@ import { useCallback, useContext, useEffect, useRef, useState } from 'react';
|
|||||||
export default function NoteConnector() {
|
export default function NoteConnector() {
|
||||||
const [pool, relays]: any = useContext(RelayContext);
|
const [pool, relays]: any = useContext(RelayContext);
|
||||||
|
|
||||||
|
const setLastLoginAtom = useSetAtom(lastLoginAtom);
|
||||||
const setHasNewerNote = useSetAtom(hasNewerNoteAtom);
|
const setHasNewerNote = useSetAtom(hasNewerNoteAtom);
|
||||||
const activeAccount: any = useAtomValue(activeAccountAtom);
|
const activeAccount: any = useAtomValue(activeAccountAtom);
|
||||||
|
|
||||||
@ -44,7 +45,7 @@ export default function NoteConnector() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
subscribe();
|
subscribe();
|
||||||
getCurrent().listen(TauriEvent.WINDOW_CLOSE_REQUESTED, () => {
|
getCurrent().listen(TauriEvent.WINDOW_CLOSE_REQUESTED, () => {
|
||||||
updateLastLoginTime(now.current);
|
setLastLoginAtom(now.current);
|
||||||
appWindow.close();
|
appWindow.close();
|
||||||
});
|
});
|
||||||
}, [activeAccount.id, pool, relays, setHasNewerNote, subscribe]);
|
}, [activeAccount.id, pool, relays, setHasNewerNote, subscribe]);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import BaseLayout from '@layouts/base';
|
import BaseLayout from '@layouts/base';
|
||||||
|
|
||||||
import { activeAccountAtom } from '@stores/account';
|
import { activeAccountAtom, activeAccountFollowsAtom } from '@stores/account';
|
||||||
|
|
||||||
import LumeSymbol from '@assets/icons/Lume';
|
import LumeSymbol from '@assets/icons/Lume';
|
||||||
|
|
||||||
@ -11,16 +11,26 @@ import { JSXElementConstructor, ReactElement, ReactFragment, ReactPortal, useCal
|
|||||||
export default function Page() {
|
export default function Page() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const setActiveAccount = useSetAtom(activeAccountAtom);
|
const setActiveAccount = useSetAtom(activeAccountAtom);
|
||||||
|
const setActiveAccountFollows = useSetAtom(activeAccountFollowsAtom);
|
||||||
|
|
||||||
const fetchActiveAccount = useCallback(async () => {
|
const fetchActiveAccount = useCallback(async () => {
|
||||||
const { getAccount } = await import('@utils/bindings');
|
const { getAccount } = await import('@utils/bindings');
|
||||||
return await getAccount();
|
return await getAccount();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const fetchFollowsByAccount = useCallback(async (id) => {
|
||||||
|
const { getFollows } = await import('@utils/bindings');
|
||||||
|
return await getFollows({ account_id: id });
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchActiveAccount()
|
fetchActiveAccount()
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
if (res.length > 0) {
|
if (res.length > 0) {
|
||||||
|
// fetch follows
|
||||||
|
fetchFollowsByAccount(res[0].id).then((follows) => {
|
||||||
|
setActiveAccountFollows(follows);
|
||||||
|
});
|
||||||
// update local storage
|
// update local storage
|
||||||
setActiveAccount(res[0]);
|
setActiveAccount(res[0]);
|
||||||
// redirect
|
// redirect
|
||||||
@ -30,7 +40,7 @@ export default function Page() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
}, [fetchActiveAccount, setActiveAccount, router]);
|
}, [fetchActiveAccount, setActiveAccount, fetchFollowsByAccount, setActiveAccountFollows, router]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative h-full overflow-hidden">
|
<div className="relative h-full overflow-hidden">
|
||||||
|
@ -2,12 +2,10 @@ import BaseLayout from '@layouts/base';
|
|||||||
|
|
||||||
import { RelayContext } from '@components/relaysProvider';
|
import { RelayContext } from '@components/relaysProvider';
|
||||||
|
|
||||||
import { activeAccountAtom } from '@stores/account';
|
import { activeAccountAtom, activeAccountFollowsAtom, lastLoginAtom } from '@stores/account';
|
||||||
import { relaysAtom } from '@stores/relays';
|
|
||||||
|
|
||||||
import { dateToUnix, hoursAgo } from '@utils/getDate';
|
import { dateToUnix, hoursAgo } from '@utils/getDate';
|
||||||
import { countTotalNotes, createCacheNote, getAllFollowsByID, getLastLoginTime } from '@utils/storage';
|
import { getParentID, pubkeyArray } from '@utils/transform';
|
||||||
import { pubkeyArray } from '@utils/transform';
|
|
||||||
|
|
||||||
import LumeSymbol from '@assets/icons/Lume';
|
import LumeSymbol from '@assets/icons/Lume';
|
||||||
|
|
||||||
@ -30,64 +28,75 @@ export default function Page() {
|
|||||||
const [pool, relays]: any = useContext(RelayContext);
|
const [pool, relays]: any = useContext(RelayContext);
|
||||||
|
|
||||||
const activeAccount: any = useAtomValue(activeAccountAtom);
|
const activeAccount: any = useAtomValue(activeAccountAtom);
|
||||||
const [done, setDone] = useState(false);
|
const activeAccountFollows: any = useAtomValue(activeAccountFollowsAtom);
|
||||||
|
const lastLogin: any = useAtomValue(lastLoginAtom);
|
||||||
|
|
||||||
const now = useRef(new Date());
|
const now = useRef(new Date());
|
||||||
const unsubscribe = useRef(null);
|
const unsubscribe = useRef(null);
|
||||||
const timer = useRef(null);
|
|
||||||
|
const [eose, setEose] = useState(false);
|
||||||
|
|
||||||
const fetchData = useCallback(
|
const fetchData = useCallback(
|
||||||
(since) => {
|
async (since) => {
|
||||||
getAllFollowsByID(activeAccount.id).then((follows) => {
|
const { createNote } = await import('@utils/bindings');
|
||||||
unsubscribe.current = pool.subscribe(
|
unsubscribe.current = pool.subscribe(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
kinds: [1],
|
kinds: [1],
|
||||||
authors: pubkeyArray(follows),
|
authors: pubkeyArray(activeAccountFollows),
|
||||||
since: dateToUnix(since),
|
since: dateToUnix(since),
|
||||||
until: dateToUnix(now.current),
|
until: dateToUnix(now.current),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
relays,
|
relays,
|
||||||
(event) => {
|
(event) => {
|
||||||
|
const parentID = getParentID(event.tags, event.id);
|
||||||
// insert event to local database
|
// insert event to local database
|
||||||
createCacheNote(event);
|
createNote({
|
||||||
|
event_id: event.id,
|
||||||
|
pubkey: event.pubkey,
|
||||||
|
kind: event.kind,
|
||||||
|
tags: JSON.stringify(event.tags),
|
||||||
|
content: event.content,
|
||||||
|
parent_id: parentID,
|
||||||
|
parent_comment_id: 'aaa',
|
||||||
|
account_id: activeAccount.id,
|
||||||
|
}).catch(console.error);
|
||||||
},
|
},
|
||||||
undefined,
|
undefined,
|
||||||
() => {
|
() => {
|
||||||
// wait for 8 seconds
|
setEose(true);
|
||||||
timer.current = setTimeout(() => setDone(true), 8000);
|
|
||||||
},
|
|
||||||
{
|
|
||||||
unsubscribeOnEose: true,
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
|
||||||
},
|
},
|
||||||
[activeAccount.id, pool, relays]
|
[activeAccount.id, activeAccountFollows, pool, relays]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
const isNoteExist = useCallback(async () => {
|
||||||
if (!done) {
|
const { checkNote } = await import('@utils/bindings');
|
||||||
countTotalNotes().then((count) => {
|
checkNote()
|
||||||
if (count.total === 0) {
|
.then((res) => {
|
||||||
fetchData(hoursAgo(24, now.current));
|
if (res.length === 5) {
|
||||||
} else {
|
const parseDate = new Date(lastLogin);
|
||||||
getLastLoginTime().then((time) => {
|
|
||||||
const parseDate = new Date(time.setting_value);
|
|
||||||
fetchData(parseDate);
|
fetchData(parseDate);
|
||||||
});
|
} else {
|
||||||
|
fetchData(hoursAgo(24, now.current));
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
.catch(console.error);
|
||||||
|
}, [fetchData, lastLogin]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (eose === false) {
|
||||||
|
isNoteExist();
|
||||||
} else {
|
} else {
|
||||||
router.replace('/newsfeed/following');
|
router.replace('/newsfeed/following');
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
unsubscribe.current;
|
unsubscribe.current;
|
||||||
clearTimeout(timer.current);
|
|
||||||
};
|
};
|
||||||
}, [activeAccount.id, done, pool, relays, router, fetchData]);
|
}, [router, eose, isNoteExist]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative h-full overflow-hidden">
|
<div className="relative h-full overflow-hidden">
|
||||||
|
@ -41,7 +41,7 @@ export default function Page() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// auto-generated profile metadata
|
// auto-generated profile metadata
|
||||||
const metadata = useMemo(
|
const metadata: any = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
display_name: name,
|
display_name: name,
|
||||||
name: name,
|
name: name,
|
||||||
@ -77,7 +77,7 @@ export default function Page() {
|
|||||||
event.sig = signEvent(event, privKey);
|
event.sig = signEvent(event, privKey);
|
||||||
|
|
||||||
// insert to database then broadcast
|
// insert to database then broadcast
|
||||||
createAccount({ pubkey: pubKey, privkey: privKey, metadata: JSON.stringify(metadata) })
|
createAccount({ pubkey: pubKey, privkey: privKey, metadata: metadata })
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
pool.publish(event, relays);
|
pool.publish(event, relays);
|
||||||
router.push({
|
router.push({
|
||||||
|
@ -85,7 +85,9 @@ export default function Page() {
|
|||||||
|
|
||||||
for (const follow of follows) {
|
for (const follow of follows) {
|
||||||
const metadata: any = await fetchMetadata(follow, pool, relays);
|
const metadata: any = await fetchMetadata(follow, pool, relays);
|
||||||
createFollow({ pubkey: follow, kind: 0, metadata: metadata.content, account_id: parseInt(id) });
|
createFollow({ pubkey: follow, kind: 0, metadata: metadata.content, account_id: parseInt(id) }).catch(
|
||||||
|
console.error
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// build event
|
// build event
|
||||||
|
@ -2,6 +2,8 @@ import BaseLayout from '@layouts/base';
|
|||||||
|
|
||||||
import { RelayContext } from '@components/relaysProvider';
|
import { RelayContext } from '@components/relaysProvider';
|
||||||
|
|
||||||
|
import { DEFAULT_AVATAR } from '@stores/constants';
|
||||||
|
|
||||||
import { fetchMetadata } from '@utils/metadata';
|
import { fetchMetadata } from '@utils/metadata';
|
||||||
import { truncate } from '@utils/truncate';
|
import { truncate } from '@utils/truncate';
|
||||||
|
|
||||||
@ -27,29 +29,34 @@ export default function Page() {
|
|||||||
const privkey: any = router.query.privkey || null;
|
const privkey: any = router.query.privkey || null;
|
||||||
const pubkey = privkey ? getPublicKey(privkey) : null;
|
const pubkey = privkey ? getPublicKey(privkey) : null;
|
||||||
|
|
||||||
const [profile, setProfile] = useState(null);
|
const [profile, setProfile] = useState({ id: null, metadata: null });
|
||||||
const [done, setDone] = useState(false);
|
const [done, setDone] = useState(false);
|
||||||
|
|
||||||
const accountId = useRef(null);
|
|
||||||
|
|
||||||
const insertAccountToStorage = useCallback(async (pubkey, privkey, metadata) => {
|
const insertAccountToStorage = useCallback(async (pubkey, privkey, metadata) => {
|
||||||
const { createAccount } = await import('@utils/bindings');
|
const { createAccount } = await import('@utils/bindings');
|
||||||
createAccount({ pubkey: pubkey, privkey: privkey, metadata: JSON.stringify(metadata) }).then(
|
createAccount({ pubkey: pubkey, privkey: privkey, metadata: metadata })
|
||||||
(res) => (accountId.current = res.id)
|
.then((res) =>
|
||||||
);
|
setProfile({
|
||||||
|
id: res.id,
|
||||||
|
metadata: JSON.parse(res.metadata),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.catch(console.error);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const insertFollowsToStorage = useCallback(
|
const insertFollowsToStorage = useCallback(
|
||||||
async (tags) => {
|
async (tags) => {
|
||||||
const { createFollow } = await import('@utils/bindings');
|
const { createFollow } = await import('@utils/bindings');
|
||||||
if (accountId.current !== null) {
|
if (profile?.id !== null) {
|
||||||
for (const tag of tags) {
|
for (const tag of tags) {
|
||||||
const metadata: any = await fetchMetadata(tag[1], pool, relays);
|
const metadata: any = await fetchMetadata(tag[1], pool, relays);
|
||||||
createFollow({ pubkey: tag[1], kind: 0, metadata: metadata.content, account_id: accountId.current });
|
createFollow({ pubkey: tag[1], kind: 0, metadata: metadata.content, account_id: profile.id }).catch(
|
||||||
|
console.error
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[pool, relays]
|
[pool, profile.id, relays]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -64,7 +71,6 @@ export default function Page() {
|
|||||||
relays,
|
relays,
|
||||||
(event: any) => {
|
(event: any) => {
|
||||||
if (event.kind === 0) {
|
if (event.kind === 0) {
|
||||||
setProfile(JSON.parse(event.content));
|
|
||||||
insertAccountToStorage(pubkey, privkey, event.content);
|
insertAccountToStorage(pubkey, privkey, event.content);
|
||||||
} else {
|
} else {
|
||||||
if (event.tags.length > 0) {
|
if (event.tags.length > 0) {
|
||||||
@ -75,9 +81,6 @@ export default function Page() {
|
|||||||
undefined,
|
undefined,
|
||||||
() => {
|
() => {
|
||||||
setDone(true);
|
setDone(true);
|
||||||
},
|
|
||||||
{
|
|
||||||
unsubscribeOnEose: true,
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -106,13 +109,20 @@ export default function Page() {
|
|||||||
<div className="w-full rounded-lg bg-zinc-900 p-4 shadow-input ring-1 ring-zinc-800">
|
<div className="w-full rounded-lg bg-zinc-900 p-4 shadow-input ring-1 ring-zinc-800">
|
||||||
<div className="flex space-x-4">
|
<div className="flex space-x-4">
|
||||||
<div className="relative h-10 w-10 rounded-full">
|
<div className="relative h-10 w-10 rounded-full">
|
||||||
<Image className="inline-block rounded-full" src={profile?.picture} alt="" fill={true} />
|
<Image
|
||||||
|
className="inline-block rounded-full"
|
||||||
|
src={profile.metadata?.picture || DEFAULT_AVATAR}
|
||||||
|
alt=""
|
||||||
|
fill={true}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 space-y-4 py-1">
|
<div className="flex-1 space-y-4 py-1">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<p className="font-semibold">{profile?.display_name || profile?.name}</p>
|
<p className="font-semibold">{profile.metadata?.display_name || profile.metadata?.name}</p>
|
||||||
<span className="leading-tight text-zinc-500">·</span>
|
<span className="leading-tight text-zinc-500">·</span>
|
||||||
<p className="text-zinc-500">@{profile?.username || (pubkey && truncate(pubkey, 16, ' .... '))}</p>
|
<p className="text-zinc-500">
|
||||||
|
@{profile.metadata?.username || (pubkey && truncate(pubkey, 16, ' .... '))}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div className="grid grid-cols-3 gap-4">
|
<div className="grid grid-cols-3 gap-4">
|
||||||
|
@ -10,3 +10,5 @@ const createMyJsonStorage = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const activeAccountAtom = atomWithStorage('activeAccount', {}, createMyJsonStorage());
|
export const activeAccountAtom = atomWithStorage('activeAccount', {}, createMyJsonStorage());
|
||||||
|
export const activeAccountFollowsAtom = atomWithStorage('activeAccountFollows', [], createMyJsonStorage());
|
||||||
|
export const lastLoginAtom = atomWithStorage('lastLoginAtom', [], createMyJsonStorage());
|
||||||
|
@ -16,11 +16,50 @@ export function createAccount(data: CreateAccountData) {
|
|||||||
return invoke<Account>('create_account', { data });
|
return invoke<Account>('create_account', { data });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getFollows(data: GetFollowData) {
|
||||||
|
return invoke<Follow[]>('get_follows', { data });
|
||||||
|
}
|
||||||
|
|
||||||
export function createFollow(data: CreateFollowData) {
|
export function createFollow(data: CreateFollowData) {
|
||||||
return invoke<Follow>('create_follow', { data });
|
return invoke<Follow>('create_follow', { data });
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Account = { id: number; pubkey: string; privkey: string; active: boolean; metadata: string };
|
export function createNote(data: CreateNoteData) {
|
||||||
export type Follow = { id: number; pubkey: string; kind: number; metadata: string; accountId: number };
|
return invoke<Note>('create_note', { data });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getNotes() {
|
||||||
|
return invoke<Note[]>('get_notes');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function checkNote() {
|
||||||
|
return invoke<Note[]>('check_note');
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GetFollowData = { account_id: number };
|
||||||
|
export type Note = {
|
||||||
|
id: number;
|
||||||
|
eventId: string;
|
||||||
|
pubkey: string;
|
||||||
|
kind: number;
|
||||||
|
tags: string;
|
||||||
|
content: string;
|
||||||
|
parent_id: string;
|
||||||
|
parent_comment_id: string;
|
||||||
|
createdAt: string;
|
||||||
|
accountId: number;
|
||||||
|
};
|
||||||
export type CreateFollowData = { pubkey: string; kind: number; metadata: string; account_id: number };
|
export type CreateFollowData = { pubkey: string; kind: number; metadata: string; account_id: number };
|
||||||
|
export type Account = { id: number; pubkey: string; privkey: string; active: boolean; metadata: string };
|
||||||
|
export type CreateNoteData = {
|
||||||
|
event_id: string;
|
||||||
|
pubkey: string;
|
||||||
|
kind: number;
|
||||||
|
tags: string;
|
||||||
|
content: string;
|
||||||
|
parent_id: string;
|
||||||
|
parent_comment_id: string;
|
||||||
|
account_id: number;
|
||||||
|
};
|
||||||
export type CreateAccountData = { pubkey: string; privkey: string; metadata: string };
|
export type CreateAccountData = { pubkey: string; privkey: string; metadata: string };
|
||||||
|
export type Follow = { id: number; pubkey: string; kind: number; metadata: string; accountId: number };
|
||||||
|
Loading…
Reference in New Issue
Block a user