mirror of
https://github.com/lumehq/lume.git
synced 2025-10-03 20:53:07 +02:00
refactor channel
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
"dependencies": {
|
||||
"@floating-ui/react": "^0.23.1",
|
||||
"@headlessui/react": "^1.7.15",
|
||||
"@nostr-dev-kit/ndk": "^0.5.2",
|
||||
"@nostr-dev-kit/ndk": "^0.5.3",
|
||||
"@tanstack/react-virtual": "3.0.0-beta.54",
|
||||
"@tauri-apps/api": "^1.4.0",
|
||||
"@vidstack/react": "^0.4.5",
|
||||
|
98
pnpm-lock.yaml
generated
98
pnpm-lock.yaml
generated
@@ -8,8 +8,8 @@ dependencies:
|
||||
specifier: ^1.7.15
|
||||
version: 1.7.15(react-dom@18.2.0)(react@18.2.0)
|
||||
'@nostr-dev-kit/ndk':
|
||||
specifier: ^0.5.2
|
||||
version: 0.5.2(typescript@4.9.5)
|
||||
specifier: ^0.5.3
|
||||
version: 0.5.3(typescript@4.9.5)
|
||||
'@tanstack/react-virtual':
|
||||
specifier: 3.0.0-beta.54
|
||||
version: 3.0.0-beta.54(react@18.2.0)
|
||||
@@ -370,13 +370,13 @@ packages:
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@eslint-community/eslint-utils@4.4.0(eslint@8.42.0):
|
||||
/@eslint-community/eslint-utils@4.4.0(eslint@8.43.0):
|
||||
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
peerDependencies:
|
||||
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
|
||||
dependencies:
|
||||
eslint: 8.42.0
|
||||
eslint: 8.43.0
|
||||
eslint-visitor-keys: 3.4.1
|
||||
dev: false
|
||||
|
||||
@@ -402,8 +402,8 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/@eslint/js@8.42.0:
|
||||
resolution: {integrity: sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==}
|
||||
/@eslint/js@8.43.0:
|
||||
resolution: {integrity: sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
dev: false
|
||||
|
||||
@@ -571,20 +571,20 @@ packages:
|
||||
'@nodelib/fs.scandir': 2.1.5
|
||||
fastq: 1.15.0
|
||||
|
||||
/@nostr-dev-kit/ndk@0.5.2(typescript@4.9.5):
|
||||
resolution: {integrity: sha512-ZTcEGHxe/Yoazr2SHB+6wQ/1ZkLvaJVdEFNOwg2Ll1lD6C7ttnP/rPD1ex17bQFaU//4yvsdgEREDJqo+mLedw==}
|
||||
/@nostr-dev-kit/ndk@0.5.3(typescript@4.9.5):
|
||||
resolution: {integrity: sha512-GLmuAoor4oMxxKjFeZ4viHR9XEI61m0wBm78vTUzY1Ev+bBdDzorv6heBz7TWmQirtoJ32r/zIgWdzHsHC6h3A==}
|
||||
dependencies:
|
||||
'@noble/hashes': 1.3.1
|
||||
'@noble/secp256k1': 2.0.0
|
||||
'@scure/base': 1.1.1
|
||||
'@typescript-eslint/eslint-plugin': 5.59.11(@typescript-eslint/parser@5.59.11)(eslint@8.42.0)(typescript@4.9.5)
|
||||
'@typescript-eslint/parser': 5.59.11(eslint@8.42.0)(typescript@4.9.5)
|
||||
'@typescript-eslint/eslint-plugin': 5.59.11(@typescript-eslint/parser@5.59.11)(eslint@8.43.0)(typescript@4.9.5)
|
||||
'@typescript-eslint/parser': 5.59.11(eslint@8.43.0)(typescript@4.9.5)
|
||||
debug: 4.3.4
|
||||
esbuild: 0.17.19
|
||||
esbuild-plugin-alias: 0.2.1
|
||||
eslint: 8.42.0
|
||||
eslint-config-prettier: 8.8.0(eslint@8.42.0)
|
||||
eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.59.11)(eslint@8.42.0)
|
||||
eslint: 8.43.0
|
||||
eslint-config-prettier: 8.8.0(eslint@8.43.0)
|
||||
eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.59.11)(eslint@8.43.0)
|
||||
esm-loader-typescript: 1.0.4
|
||||
eventemitter3: 5.0.1
|
||||
light-bolt11-decoder: 3.0.0
|
||||
@@ -1023,7 +1023,7 @@ packages:
|
||||
resolution: {integrity: sha512-W8F4eoTIvzXeNrT3JroQPimZLXnlJA8smYygHZUKFPVoYwgs/OhJkA1VBhL3iSs57OQkuINqHlY4SmMT5wtnJg==}
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/eslint-plugin@5.59.11(@typescript-eslint/parser@5.59.11)(eslint@8.42.0)(typescript@4.9.5):
|
||||
/@typescript-eslint/eslint-plugin@5.59.11(@typescript-eslint/parser@5.59.11)(eslint@8.43.0)(typescript@4.9.5):
|
||||
resolution: {integrity: sha512-XxuOfTkCUiOSyBWIvHlUraLw/JT/6Io1365RO6ZuI88STKMavJZPNMU0lFcUTeQXEhHiv64CbxYxBNoDVSmghg==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
peerDependencies:
|
||||
@@ -1035,12 +1035,12 @@ packages:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.5.1
|
||||
'@typescript-eslint/parser': 5.59.11(eslint@8.42.0)(typescript@4.9.5)
|
||||
'@typescript-eslint/parser': 5.59.11(eslint@8.43.0)(typescript@4.9.5)
|
||||
'@typescript-eslint/scope-manager': 5.59.11
|
||||
'@typescript-eslint/type-utils': 5.59.11(eslint@8.42.0)(typescript@4.9.5)
|
||||
'@typescript-eslint/utils': 5.59.11(eslint@8.42.0)(typescript@4.9.5)
|
||||
'@typescript-eslint/type-utils': 5.59.11(eslint@8.43.0)(typescript@4.9.5)
|
||||
'@typescript-eslint/utils': 5.59.11(eslint@8.43.0)(typescript@4.9.5)
|
||||
debug: 4.3.4
|
||||
eslint: 8.42.0
|
||||
eslint: 8.43.0
|
||||
grapheme-splitter: 1.0.4
|
||||
ignore: 5.2.4
|
||||
natural-compare-lite: 1.4.0
|
||||
@@ -1051,7 +1051,7 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/@typescript-eslint/parser@5.59.11(eslint@8.42.0)(typescript@4.9.5):
|
||||
/@typescript-eslint/parser@5.59.11(eslint@8.43.0)(typescript@4.9.5):
|
||||
resolution: {integrity: sha512-s9ZF3M+Nym6CAZEkJJeO2TFHHDsKAM3ecNkLuH4i4s8/RCPnF5JRip2GyviYkeEAcwGMJxkqG9h2dAsnA1nZpA==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
peerDependencies:
|
||||
@@ -1065,7 +1065,7 @@ packages:
|
||||
'@typescript-eslint/types': 5.59.11
|
||||
'@typescript-eslint/typescript-estree': 5.59.11(typescript@4.9.5)
|
||||
debug: 4.3.4
|
||||
eslint: 8.42.0
|
||||
eslint: 8.43.0
|
||||
typescript: 4.9.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -1079,7 +1079,7 @@ packages:
|
||||
'@typescript-eslint/visitor-keys': 5.59.11
|
||||
dev: false
|
||||
|
||||
/@typescript-eslint/type-utils@5.59.11(eslint@8.42.0)(typescript@4.9.5):
|
||||
/@typescript-eslint/type-utils@5.59.11(eslint@8.43.0)(typescript@4.9.5):
|
||||
resolution: {integrity: sha512-LZqVY8hMiVRF2a7/swmkStMYSoXMFlzL6sXV6U/2gL5cwnLWQgLEG8tjWPpaE4rMIdZ6VKWwcffPlo1jPfk43g==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
peerDependencies:
|
||||
@@ -1090,9 +1090,9 @@ packages:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/typescript-estree': 5.59.11(typescript@4.9.5)
|
||||
'@typescript-eslint/utils': 5.59.11(eslint@8.42.0)(typescript@4.9.5)
|
||||
'@typescript-eslint/utils': 5.59.11(eslint@8.43.0)(typescript@4.9.5)
|
||||
debug: 4.3.4
|
||||
eslint: 8.42.0
|
||||
eslint: 8.43.0
|
||||
tsutils: 3.21.0(typescript@4.9.5)
|
||||
typescript: 4.9.5
|
||||
transitivePeerDependencies:
|
||||
@@ -1125,19 +1125,19 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/@typescript-eslint/utils@5.59.11(eslint@8.42.0)(typescript@4.9.5):
|
||||
/@typescript-eslint/utils@5.59.11(eslint@8.43.0)(typescript@4.9.5):
|
||||
resolution: {integrity: sha512-didu2rHSOMUdJThLk4aZ1Or8IcO3HzCw/ZvEjTTIfjIrcdd5cvSIwwDy2AOlE7htSNp7QIZ10fLMyRCveesMLg==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
peerDependencies:
|
||||
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.4.0(eslint@8.42.0)
|
||||
'@eslint-community/eslint-utils': 4.4.0(eslint@8.43.0)
|
||||
'@types/json-schema': 7.0.12
|
||||
'@types/semver': 7.5.0
|
||||
'@typescript-eslint/scope-manager': 5.59.11
|
||||
'@typescript-eslint/types': 5.59.11
|
||||
'@typescript-eslint/typescript-estree': 5.59.11(typescript@4.9.5)
|
||||
eslint: 8.42.0
|
||||
eslint: 8.43.0
|
||||
eslint-scope: 5.1.1
|
||||
semver: 7.5.2
|
||||
transitivePeerDependencies:
|
||||
@@ -1185,16 +1185,16 @@ packages:
|
||||
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
|
||||
dev: false
|
||||
|
||||
/acorn-jsx@5.3.2(acorn@8.8.2):
|
||||
/acorn-jsx@5.3.2(acorn@8.9.0):
|
||||
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
||||
peerDependencies:
|
||||
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||
dependencies:
|
||||
acorn: 8.8.2
|
||||
acorn: 8.9.0
|
||||
dev: false
|
||||
|
||||
/acorn@8.8.2:
|
||||
resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==}
|
||||
/acorn@8.9.0:
|
||||
resolution: {integrity: sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
hasBin: true
|
||||
|
||||
@@ -1415,7 +1415,7 @@ packages:
|
||||
hasBin: true
|
||||
dependencies:
|
||||
caniuse-lite: 1.0.30001503
|
||||
electron-to-chromium: 1.4.431
|
||||
electron-to-chromium: 1.4.433
|
||||
node-releases: 2.0.12
|
||||
update-browserslist-db: 1.0.11(browserslist@4.21.9)
|
||||
dev: true
|
||||
@@ -1780,8 +1780,8 @@ packages:
|
||||
/eastasianwidth@0.2.0:
|
||||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||
|
||||
/electron-to-chromium@1.4.431:
|
||||
resolution: {integrity: sha512-m232JTVmCawA2vG+1azVxhKZ9Sv1Q//xxNv5PkP5rWxGgQE8c3CiZFrh8Xnp+d1NmNxlu3QQrGIfdeW5TtXX5w==}
|
||||
/electron-to-chromium@1.4.433:
|
||||
resolution: {integrity: sha512-MGO1k0w1RgrfdbLVwmXcDhHHuxCn2qRgR7dYsJvWFKDttvYPx6FNzCGG0c/fBBvzK2LDh3UV7Tt9awnHnvAAUQ==}
|
||||
dev: true
|
||||
|
||||
/emoji-regex@8.0.0:
|
||||
@@ -1951,13 +1951,13 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
dev: false
|
||||
|
||||
/eslint-config-prettier@8.8.0(eslint@8.42.0):
|
||||
/eslint-config-prettier@8.8.0(eslint@8.43.0):
|
||||
resolution: {integrity: sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
eslint: '>=7.0.0'
|
||||
dependencies:
|
||||
eslint: 8.42.0
|
||||
eslint: 8.43.0
|
||||
dev: false
|
||||
|
||||
/eslint-formatter-pretty@4.1.0:
|
||||
@@ -1984,7 +1984,7 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/eslint-module-utils@2.8.0(@typescript-eslint/parser@5.59.11)(eslint-import-resolver-node@0.3.7)(eslint@8.42.0):
|
||||
/eslint-module-utils@2.8.0(@typescript-eslint/parser@5.59.11)(eslint-import-resolver-node@0.3.7)(eslint@8.43.0):
|
||||
resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==}
|
||||
engines: {node: '>=4'}
|
||||
peerDependencies:
|
||||
@@ -2005,15 +2005,15 @@ packages:
|
||||
eslint-import-resolver-webpack:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/parser': 5.59.11(eslint@8.42.0)(typescript@4.9.5)
|
||||
'@typescript-eslint/parser': 5.59.11(eslint@8.43.0)(typescript@4.9.5)
|
||||
debug: 3.2.7
|
||||
eslint: 8.42.0
|
||||
eslint: 8.43.0
|
||||
eslint-import-resolver-node: 0.3.7
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.59.11)(eslint@8.42.0):
|
||||
/eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.59.11)(eslint@8.43.0):
|
||||
resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==}
|
||||
engines: {node: '>=4'}
|
||||
peerDependencies:
|
||||
@@ -2023,15 +2023,15 @@ packages:
|
||||
'@typescript-eslint/parser':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/parser': 5.59.11(eslint@8.42.0)(typescript@4.9.5)
|
||||
'@typescript-eslint/parser': 5.59.11(eslint@8.43.0)(typescript@4.9.5)
|
||||
array-includes: 3.1.6
|
||||
array.prototype.flat: 1.3.1
|
||||
array.prototype.flatmap: 1.3.1
|
||||
debug: 3.2.7
|
||||
doctrine: 2.1.0
|
||||
eslint: 8.42.0
|
||||
eslint: 8.43.0
|
||||
eslint-import-resolver-node: 0.3.7
|
||||
eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.59.11)(eslint-import-resolver-node@0.3.7)(eslint@8.42.0)
|
||||
eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.59.11)(eslint-import-resolver-node@0.3.7)(eslint@8.43.0)
|
||||
has: 1.0.3
|
||||
is-core-module: 2.12.1
|
||||
is-glob: 4.0.3
|
||||
@@ -2071,15 +2071,15 @@ packages:
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
dev: false
|
||||
|
||||
/eslint@8.42.0:
|
||||
resolution: {integrity: sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==}
|
||||
/eslint@8.43.0:
|
||||
resolution: {integrity: sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.4.0(eslint@8.42.0)
|
||||
'@eslint-community/eslint-utils': 4.4.0(eslint@8.43.0)
|
||||
'@eslint-community/regexpp': 4.5.1
|
||||
'@eslint/eslintrc': 2.0.3
|
||||
'@eslint/js': 8.42.0
|
||||
'@eslint/js': 8.43.0
|
||||
'@humanwhocodes/config-array': 0.11.10
|
||||
'@humanwhocodes/module-importer': 1.0.1
|
||||
'@nodelib/fs.walk': 1.2.8
|
||||
@@ -2132,8 +2132,8 @@ packages:
|
||||
resolution: {integrity: sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
dependencies:
|
||||
acorn: 8.8.2
|
||||
acorn-jsx: 5.3.2(acorn@8.8.2)
|
||||
acorn: 8.9.0
|
||||
acorn-jsx: 5.3.2(acorn@8.9.0)
|
||||
eslint-visitor-keys: 3.4.1
|
||||
dev: false
|
||||
|
||||
@@ -4686,7 +4686,7 @@ packages:
|
||||
'@brillout/json-serializer': 0.5.3
|
||||
'@brillout/picocolors': 1.0.4
|
||||
'@brillout/vite-plugin-import-build': 0.2.18
|
||||
acorn: 8.8.2
|
||||
acorn: 8.9.0
|
||||
cac: 6.7.14
|
||||
es-module-lexer: 0.10.5
|
||||
esbuild: 0.17.19
|
||||
|
@@ -18,25 +18,6 @@ VALUES
|
||||
1681898574
|
||||
);
|
||||
|
||||
INSERT
|
||||
OR IGNORE INTO channels (
|
||||
event_id,
|
||||
pubkey,
|
||||
name,
|
||||
about,
|
||||
picture,
|
||||
created_at
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
"42224859763652914db53052103f0b744df79dfc4efef7e950fc0802fc3df3c5",
|
||||
"460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c",
|
||||
"Amethyst Users",
|
||||
"General discussion about the Amethyst Nostr client for Android",
|
||||
"https://nostr.build/i/5970.png",
|
||||
1674092111
|
||||
);
|
||||
|
||||
INSERT
|
||||
OR IGNORE INTO channels (
|
||||
event_id,
|
||||
|
15
src-tauri/migrations/20230617003135_add_channel_messages.sql
Normal file
15
src-tauri/migrations/20230617003135_add_channel_messages.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
-- Add migration script here
|
||||
CREATE TABLE
|
||||
channel_messages (
|
||||
id INTEGER NOT NULL PRIMARY KEY,
|
||||
channel_id TEXT NOT NULL,
|
||||
event_id TEXT NOT NULL UNIQUE,
|
||||
pubkey TEXT NOT NULL,
|
||||
kind INTEGER NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
tags JSON,
|
||||
mute BOOLEAN DEFAULT 0,
|
||||
hide BOOLEAN DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
FOREIGN KEY (channel_id) REFERENCES channels (event_id)
|
||||
);
|
@@ -93,6 +93,12 @@ fn main() {
|
||||
sql: include_str!("../migrations/20230521092300_add_block_model.sql"),
|
||||
kind: MigrationKind::Up,
|
||||
},
|
||||
Migration {
|
||||
version: 20230617003135,
|
||||
description: "add channel messages",
|
||||
sql: include_str!("../migrations/20230617003135_add_channel_messages.sql"),
|
||||
kind: MigrationKind::Up,
|
||||
},
|
||||
],
|
||||
)
|
||||
.build(),
|
||||
|
@@ -1,72 +0,0 @@
|
||||
import { ChannelMessageItem } from "@app/channel/components/messages/item";
|
||||
import { useChannelMessages } from "@stores/channels";
|
||||
import { getHourAgo } from "@utils/date";
|
||||
import { useCallback, useRef } from "react";
|
||||
import { Virtuoso } from "react-virtuoso";
|
||||
|
||||
export function ChannelMessageList() {
|
||||
const now = useRef(new Date());
|
||||
const virtuosoRef = useRef(null);
|
||||
|
||||
const messages = useChannelMessages((state: any) => state.messages);
|
||||
|
||||
const itemContent: any = useCallback(
|
||||
(index: string | number) => {
|
||||
return <ChannelMessageItem data={messages[index]} />;
|
||||
},
|
||||
[messages],
|
||||
);
|
||||
|
||||
const computeItemKey = useCallback(
|
||||
(index: string | number) => {
|
||||
return messages[index].id;
|
||||
},
|
||||
[messages],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="h-full w-full">
|
||||
<Virtuoso
|
||||
ref={virtuosoRef}
|
||||
data={[]}
|
||||
itemContent={itemContent}
|
||||
components={{
|
||||
Header: () => (
|
||||
<div className="relative py-4">
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<div className="w-full border-t border-zinc-800" />
|
||||
</div>
|
||||
<div className="relative flex justify-center">
|
||||
<div className="inline-flex items-center gap-x-1.5 rounded-full bg-zinc-900 px-3 py-1.5 text-base font-medium text-zinc-400 shadow-sm ring-1 ring-inset ring-zinc-800">
|
||||
{getHourAgo(24, now.current).toLocaleDateString("en-US", {
|
||||
weekday: "long",
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
EmptyPlaceholder: () => (
|
||||
<div className="flex flex-col gap-1 text-center">
|
||||
<h3 className="text-base font-semibold leading-none text-white">
|
||||
Nothing to see here yet
|
||||
</h3>
|
||||
<p className="text-base leading-none text-zinc-400">
|
||||
Be the first to share a message in this channel.
|
||||
</p>
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
computeItemKey={computeItemKey}
|
||||
initialTopMostItemIndex={messages.length - 1}
|
||||
alignToBottom={true}
|
||||
followOutput={true}
|
||||
overscan={50}
|
||||
increaseViewportBy={{ top: 200, bottom: 200 }}
|
||||
className="scrollbar-hide h-full w-full overflow-y-auto"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
import { UserReply } from "@app/channel/components/messages/userReply";
|
||||
import { NDKEvent, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
|
||||
import { CancelIcon } from "@shared/icons";
|
||||
import { CancelIcon, EnterIcon } from "@shared/icons";
|
||||
import { MediaUploader } from "@shared/mediaUploader";
|
||||
import { RelayContext } from "@shared/relayProvider";
|
||||
import { useActiveAccount } from "@stores/accounts";
|
||||
import { useChannelMessages } from "@stores/channels";
|
||||
@@ -17,7 +18,7 @@ export function ChannelMessageForm({ channelID }: { channelID: string }) {
|
||||
state.closeReply,
|
||||
]);
|
||||
|
||||
const submitEvent = () => {
|
||||
const submit = () => {
|
||||
let tags: string[][];
|
||||
|
||||
if (replyTo.id !== null) {
|
||||
@@ -51,7 +52,7 @@ export function ChannelMessageForm({ channelID }: { channelID: string }) {
|
||||
const handleEnterPress = (e) => {
|
||||
if (e.key === "Enter" && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
submitEvent();
|
||||
submit();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -60,11 +61,7 @@ export function ChannelMessageForm({ channelID }: { channelID: string }) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`relative ${
|
||||
replyTo.id ? "h-36" : "h-24"
|
||||
} w-full overflow-hidden before:pointer-events-none before:absolute before:-inset-1 before:rounded-[6px] before:border before:border-fuchsia-500 before:opacity-0 before:ring-2 before:ring-fuchsia-500/20 before:transition after:pointer-events-none after:absolute after:inset-px after:rounded-[7px] after:shadow-highlight after:shadow-white/5 after:transition focus-within:before:opacity-100 focus-within:after:shadow-fuchsia-500/100 dark:focus-within:after:shadow-fuchsia-500/20`}
|
||||
>
|
||||
<div className={`relative w-full ${replyTo.id ? "h-36" : "h-24"}`}>
|
||||
{replyTo.id && (
|
||||
<div className="absolute left-0 top-0 z-10 h-16 w-full p-[2px]">
|
||||
<div className="flex h-full w-full items-center justify-between rounded-t-md border-b border-zinc-700/70 bg-zinc-900 px-3">
|
||||
@@ -92,23 +89,19 @@ export function ChannelMessageForm({ channelID }: { channelID: string }) {
|
||||
placeholder="Message"
|
||||
className={`relative ${
|
||||
replyTo.id ? "h-36 pt-16" : "h-24 pt-3"
|
||||
} w-full resize-none rounded-lg border border-black/5 px-3.5 pb-3 text-base shadow-input shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-white dark:shadow-black/10 dark:placeholder:text-zinc-500`}
|
||||
} w-full resize-none rounded-md px-5 !outline-none bg-zinc-800 placeholder:text-zinc-500`}
|
||||
/>
|
||||
<div className="absolute bottom-2 w-full px-2">
|
||||
<div className="flex w-full items-center justify-between bg-zinc-800">
|
||||
<div className="flex items-center gap-2 divide-x divide-zinc-700">
|
||||
<div className="flex items-center gap-2 pl-2" />
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => submitEvent()}
|
||||
disabled={value.length === 0 ? true : false}
|
||||
className="inline-flex h-8 w-16 items-center justify-center rounded-md bg-fuchsia-500 px-4 text-base font-medium shadow-button hover:bg-fuchsia-600 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50"
|
||||
>
|
||||
Send
|
||||
</button>
|
||||
</div>
|
||||
<div className="absolute right-2 bottom-0 h-11">
|
||||
<div className="h-full flex gap-3 items-center justify-end text-zinc-500">
|
||||
<MediaUploader setState={setValue} />
|
||||
<button
|
||||
type="button"
|
||||
onClick={submit}
|
||||
className="inline-flex items-center gap-1 text-sm leading-none"
|
||||
>
|
||||
<EnterIcon width={14} height={14} className="" />
|
||||
Send
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -53,7 +53,7 @@ export function MessageHideButton({ id }: { id: string }) {
|
||||
onClick={openModal}
|
||||
className="inline-flex h-7 w-7 items-center justify-center rounded hover:bg-zinc-800"
|
||||
>
|
||||
<HideIcon width={16} height={16} className="text-white" />
|
||||
<HideIcon width={16} height={16} className="text-zinc-200" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Transition appear show={isOpen} as={Fragment}>
|
||||
|
@@ -2,22 +2,22 @@ import { MessageHideButton } from "@app/channel/components/messages/hideButton";
|
||||
import { MessageMuteButton } from "@app/channel/components/messages/muteButton";
|
||||
import { MessageReplyButton } from "@app/channel/components/messages/replyButton";
|
||||
import { ChannelMessageUser } from "@app/channel/components/messages/user";
|
||||
import { NDKEvent } from "@nostr-dev-kit/ndk";
|
||||
import { MentionNote } from "@shared/notes/mentions/note";
|
||||
import { ImagePreview } from "@shared/notes/preview/image";
|
||||
import { LinkPreview } from "@shared/notes/preview/link";
|
||||
import { VideoPreview } from "@shared/notes/preview/video";
|
||||
import { parser } from "@utils/parser";
|
||||
import { useMemo } from "react";
|
||||
import { LumeEvent } from "@utils/types";
|
||||
|
||||
export function ChannelMessageItem({ data }: { data: NDKEvent }) {
|
||||
const content = useMemo(() => parser(data), [data]);
|
||||
export function ChannelMessageItem({ data }: { data: LumeEvent }) {
|
||||
const content = parser(data);
|
||||
|
||||
return (
|
||||
<div className="group relative flex h-min min-h-min w-full select-text flex-col px-5 py-3 hover:bg-black/20">
|
||||
<div className="flex flex-col">
|
||||
<ChannelMessageUser pubkey={data.pubkey} time={data.created_at} />
|
||||
<div className="-mt-[20px] pl-[49px]">
|
||||
<p className="whitespace-pre-line break-words text-base leading-tight">
|
||||
<p className="select-text whitespace-pre-line break-words text-base text-zinc-100">
|
||||
{content.parsed}
|
||||
</p>
|
||||
{Array.isArray(content.images) && content.images.length ? (
|
||||
@@ -30,6 +30,11 @@ export function ChannelMessageItem({ data }: { data: NDKEvent }) {
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{Array.isArray(content.links) && content.links.length ? (
|
||||
<LinkPreview urls={content.links} />
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{Array.isArray(content.notes) && content.notes.length ? (
|
||||
content.notes.map((note: string) => (
|
||||
<MentionNote key={note} id={note} />
|
||||
|
@@ -53,7 +53,7 @@ export function MessageMuteButton({ pubkey }: { pubkey: string }) {
|
||||
onClick={() => openModal()}
|
||||
className="inline-flex h-7 w-7 items-center justify-center rounded hover:bg-zinc-800"
|
||||
>
|
||||
<MuteIcon width={16} height={16} className="text-white" />
|
||||
<MuteIcon width={16} height={16} className="text-zinc-200" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Transition appear show={isOpen} as={Fragment}>
|
||||
|
@@ -20,7 +20,7 @@ export function MessageReplyButton({
|
||||
onClick={() => createReply()}
|
||||
className="inline-flex h-7 w-7 items-center justify-center rounded hover:bg-zinc-800"
|
||||
>
|
||||
<ReplyMessageIcon width={16} height={16} className="text-white" />
|
||||
<ReplyMessageIcon width={16} height={16} className="text-zinc-200" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
);
|
||||
|
@@ -4,95 +4,73 @@ import { ChannelMessageForm } from "@app/channel/components/messages/form";
|
||||
import { ChannelMetadata } from "@app/channel/components/metadata";
|
||||
import { RelayContext } from "@shared/relayProvider";
|
||||
import { useChannelMessages } from "@stores/channels";
|
||||
import { useVirtualizer } from "@tanstack/react-virtual";
|
||||
import { dateToUnix, getHourAgo } from "@utils/date";
|
||||
import { dateToUnix } from "@utils/date";
|
||||
import { usePageContext } from "@utils/hooks/usePageContext";
|
||||
import { LumeEvent } from "@utils/types";
|
||||
import { useCallback, useContext, useEffect, useRef } from "react";
|
||||
import { Virtuoso } from "react-virtuoso";
|
||||
import useSWRSubscription from "swr/subscription";
|
||||
|
||||
const now = new Date();
|
||||
const since = dateToUnix(getHourAgo(24, now));
|
||||
|
||||
export function Page() {
|
||||
const ndk = useContext(RelayContext);
|
||||
const pageContext = usePageContext();
|
||||
const virtuosoRef = useRef(null);
|
||||
|
||||
const searchParams: any = pageContext.urlParsed.search;
|
||||
const channelID = searchParams.id;
|
||||
|
||||
const [messages, addMessage, fetchMessages, clearMessages]: any =
|
||||
const [messages, fetchMessages, addMessage, clearMessages] =
|
||||
useChannelMessages((state: any) => [
|
||||
state.messages,
|
||||
state.addMessage,
|
||||
state.fetch,
|
||||
state.add,
|
||||
state.clear,
|
||||
]);
|
||||
|
||||
useSWRSubscription(["channelMessagesSubscribe", channelID], () => {
|
||||
// subscribe to channel
|
||||
const sub = ndk.subscribe({
|
||||
"#e": [channelID],
|
||||
kinds: [42],
|
||||
since: dateToUnix(),
|
||||
});
|
||||
useSWRSubscription(
|
||||
channelID ? ["channelMessagesSubscribe", channelID] : null,
|
||||
() => {
|
||||
// subscribe to channel
|
||||
const sub = ndk.subscribe(
|
||||
{
|
||||
"#e": [channelID],
|
||||
kinds: [42],
|
||||
since: dateToUnix(),
|
||||
},
|
||||
{ closeOnEose: false },
|
||||
);
|
||||
|
||||
sub.addListener("event", (event) => {
|
||||
addMessage(event);
|
||||
});
|
||||
sub.addListener("event", (event: LumeEvent) => {
|
||||
addMessage(channelID, event);
|
||||
});
|
||||
|
||||
return () => {
|
||||
sub.stop();
|
||||
};
|
||||
});
|
||||
return () => {
|
||||
sub.stop();
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
fetchMessages(ndk, channelID, since);
|
||||
fetchMessages(channelID);
|
||||
|
||||
return () => {
|
||||
clearMessages();
|
||||
};
|
||||
}, [fetchMessages]);
|
||||
|
||||
const count = messages.length;
|
||||
const reverseIndex = useCallback((index) => count - 1 - index, [count]);
|
||||
const parentRef = useRef();
|
||||
const virtualizerRef = useRef(null);
|
||||
const itemContent: any = useCallback(
|
||||
(index: string | number) => {
|
||||
return <ChannelMessageItem data={messages[index]} />;
|
||||
},
|
||||
[messages],
|
||||
);
|
||||
|
||||
if (
|
||||
virtualizerRef.current &&
|
||||
count !== virtualizerRef.current.options.count
|
||||
) {
|
||||
const delta = count - virtualizerRef.current.options.count;
|
||||
const nextOffset = virtualizerRef.current.scrollOffset + delta * 200;
|
||||
|
||||
virtualizerRef.current.scrollOffset = nextOffset;
|
||||
virtualizerRef.current.scrollToOffset(nextOffset, { align: "start" });
|
||||
}
|
||||
|
||||
const virtualizer = useVirtualizer({
|
||||
count,
|
||||
getScrollElement: () => parentRef.current,
|
||||
estimateSize: () => 200,
|
||||
getItemKey: useCallback(
|
||||
(index) => messages[reverseIndex(index)].id,
|
||||
[messages, reverseIndex],
|
||||
),
|
||||
overscan: 5,
|
||||
scrollMargin: 50,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
virtualizerRef.current = virtualizer;
|
||||
}, []);
|
||||
|
||||
const items = virtualizer.getVirtualItems();
|
||||
|
||||
const [paddingTop, paddingBottom] =
|
||||
items.length > 0
|
||||
? [
|
||||
Math.max(0, items[0].start - virtualizer.options.scrollMargin),
|
||||
Math.max(0, virtualizer.getTotalSize() - items[items.length - 1].end),
|
||||
]
|
||||
: [0, 0];
|
||||
const computeItemKey = useCallback(
|
||||
(index: string | number) => {
|
||||
return messages[index].event_id;
|
||||
},
|
||||
[messages],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="h-full w-full grid grid-cols-3">
|
||||
@@ -105,40 +83,23 @@ export function Page() {
|
||||
</div>
|
||||
<div className="w-full flex-1 p-3">
|
||||
<div className="flex h-full flex-col justify-between rounded-md bg-zinc-900">
|
||||
<div
|
||||
ref={parentRef}
|
||||
className="scrollbar-hide overflow-y-auto h-full w-full"
|
||||
style={{ contain: "strict" }}
|
||||
>
|
||||
{!messages ? (
|
||||
<p>Loading...</p>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
overflowAnchor: "none",
|
||||
paddingTop,
|
||||
paddingBottom,
|
||||
}}
|
||||
>
|
||||
{items.map((item) => {
|
||||
const index = reverseIndex(item.index);
|
||||
const message = messages[index];
|
||||
|
||||
return (
|
||||
<div
|
||||
key={item.key}
|
||||
data-index={item.index}
|
||||
data-reverse-index={index}
|
||||
ref={virtualizer.measureElement}
|
||||
>
|
||||
<ChannelMessageItem data={message} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="w-full inline-flex shrink-0 border-t border-zinc-800">
|
||||
{!messages ? (
|
||||
<p>Loading...</p>
|
||||
) : (
|
||||
<Virtuoso
|
||||
ref={virtuosoRef}
|
||||
data={messages}
|
||||
itemContent={itemContent}
|
||||
computeItemKey={computeItemKey}
|
||||
initialTopMostItemIndex={messages.length - 1}
|
||||
alignToBottom={true}
|
||||
followOutput={true}
|
||||
overscan={50}
|
||||
increaseViewportBy={{ top: 200, bottom: 200 }}
|
||||
className="scrollbar-hide overflow-y-auto h-full w-full"
|
||||
/>
|
||||
)}
|
||||
<div className="w-full inline-flex shrink-0 px-5 py-3 border-t border-zinc-800">
|
||||
<ChannelMessageForm channelID={channelID} />
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -18,11 +18,11 @@ export function Page() {
|
||||
const searchParams: any = pageContext.urlParsed.search;
|
||||
const pubkey = searchParams.pubkey;
|
||||
|
||||
const [fetchMessages, clear] = useChatMessages((state: any) => [
|
||||
const [add, fetchMessages, clear] = useChatMessages((state: any) => [
|
||||
state.add,
|
||||
state.fetch,
|
||||
state.clear,
|
||||
]);
|
||||
const add = useChatMessages((state: any) => state.add);
|
||||
|
||||
useSWRSubscription(account !== pubkey ? ["chat", pubkey] : null, () => {
|
||||
const sub = ndk.subscribe({
|
||||
|
@@ -1,5 +1,11 @@
|
||||
import { prefetchEvents } from "@libs/ndk";
|
||||
import { countTotalNotes, createChat, createNote } from "@libs/storage";
|
||||
import {
|
||||
countTotalNotes,
|
||||
createChannelMessage,
|
||||
createChat,
|
||||
createNote,
|
||||
getChannels,
|
||||
} from "@libs/storage";
|
||||
import { NDKFilter } from "@nostr-dev-kit/ndk";
|
||||
import { LumeIcon } from "@shared/icons";
|
||||
import { RelayContext } from "@shared/relayProvider";
|
||||
@@ -98,12 +104,52 @@ export function Page() {
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchChannelMessages() {
|
||||
try {
|
||||
const ids = [];
|
||||
const channels: any = await getChannels(10, 0);
|
||||
channels.forEach((channel) => {
|
||||
ids.push(channel.event_id);
|
||||
});
|
||||
|
||||
const since =
|
||||
lastLogin === 0 ? dateToUnix(getHourAgo(48, now.current)) : lastLogin;
|
||||
|
||||
const filter: NDKFilter = {
|
||||
"#e": ids,
|
||||
kinds: [42],
|
||||
since: since,
|
||||
};
|
||||
|
||||
const events = await prefetchEvents(ndk, filter);
|
||||
events.forEach((event) => {
|
||||
const channel_id = event.tags[0][1];
|
||||
if (channel_id) {
|
||||
createChannelMessage(
|
||||
channel_id,
|
||||
event.id,
|
||||
event.pubkey,
|
||||
event.kind,
|
||||
event.content,
|
||||
event.tags,
|
||||
event.created_at,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.log("error: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
async function prefetch() {
|
||||
const notes = await fetchNotes();
|
||||
if (notes) {
|
||||
const chats = await fetchChats();
|
||||
if (chats) {
|
||||
const channels = await fetchChannelMessages();
|
||||
if (chats && channels) {
|
||||
navigate("/app/space", { overwriteLastHistoryEntry: true });
|
||||
}
|
||||
}
|
||||
|
@@ -35,7 +35,7 @@ export async function prefetchEvents(
|
||||
});
|
||||
|
||||
relaySetSubscription.on("eose", () => {
|
||||
setTimeout(() => resolve(new Set(events.values())), 3000);
|
||||
setTimeout(() => resolve(new Set(events.values())), 5000);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@@ -303,6 +303,31 @@ export async function updateChannelMetadata(event_id: string, value: string) {
|
||||
);
|
||||
}
|
||||
|
||||
// create channel messages
|
||||
export async function createChannelMessage(
|
||||
channel_id: string,
|
||||
event_id: string,
|
||||
pubkey: string,
|
||||
kind: number,
|
||||
content: string,
|
||||
tags: string[][],
|
||||
created_at: number,
|
||||
) {
|
||||
const db = await connect();
|
||||
return await db.execute(
|
||||
"INSERT OR IGNORE INTO channel_messages (channel_id, event_id, pubkey, kind, content, tags, created_at) VALUES (?, ?, ?, ?, ?, ?, ?);",
|
||||
[channel_id, event_id, pubkey, kind, content, tags, created_at],
|
||||
);
|
||||
}
|
||||
|
||||
// get channel messages by channel id
|
||||
export async function getChannelMessages(channel_id: string) {
|
||||
const db = await connect();
|
||||
return await db.select(
|
||||
`SELECT * FROM channel_messages WHERE channel_id = "${channel_id}" ORDER BY created_at ASC;`,
|
||||
);
|
||||
}
|
||||
|
||||
// get all chats by pubkey
|
||||
export async function getChatsByPubkey(pubkey: string) {
|
||||
const db = await connect();
|
||||
|
@@ -2,7 +2,7 @@ import { Image } from "@shared/image";
|
||||
|
||||
export function ImagePreview({ urls }: { urls: string[] }) {
|
||||
return (
|
||||
<div className="mt-3 overflow-hidden">
|
||||
<div className="mt-3 max-w-[420px] overflow-hidden">
|
||||
<div className="flex flex-col gap-2">
|
||||
{urls.map((url) => (
|
||||
<div key={url} className="min-w-0 grow-0 shrink-0 basis-full">
|
||||
|
@@ -6,7 +6,7 @@ export function LinkPreview({ urls }: { urls: string[] }) {
|
||||
const { data, error, isLoading } = useOpenGraph(urls[0]);
|
||||
|
||||
return (
|
||||
<div className="mt-3 overflow-hidden rounded-lg bg-zinc-800">
|
||||
<div className="mt-3 max-w-[420px] overflow-hidden rounded-lg bg-zinc-800">
|
||||
{error && <p>failed to load</p>}
|
||||
{isLoading || !data ? (
|
||||
<div className="flex flex-col">
|
||||
|
@@ -5,7 +5,7 @@ export function VideoPreview({ urls }: { urls: string[] }) {
|
||||
<div
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onKeyDown={(e) => e.stopPropagation()}
|
||||
className="relative mt-2 flex w-full flex-col overflow-hidden rounded-lg bg-zinc-950"
|
||||
className="relative mt-3 max-w-[420px] flex w-full flex-col overflow-hidden rounded-lg bg-zinc-950"
|
||||
>
|
||||
<MediaPlayer src={urls[0]} poster="" controls>
|
||||
<MediaOutlet />
|
||||
|
@@ -1,5 +1,9 @@
|
||||
import { getChannels } from "@libs/storage";
|
||||
import NDK, { NDKFilter } from "@nostr-dev-kit/ndk";
|
||||
import {
|
||||
createChannelMessage,
|
||||
getChannelMessages,
|
||||
getChannels,
|
||||
} from "@libs/storage";
|
||||
import { LumeEvent } from "@utils/types";
|
||||
import { create } from "zustand";
|
||||
import { immer } from "zustand/middleware/immer";
|
||||
|
||||
@@ -38,19 +42,28 @@ export const useChannelMessages = create(
|
||||
immer((set) => ({
|
||||
messages: [],
|
||||
replyTo: { id: null, pubkey: null, content: null },
|
||||
fetch: async (ndk: NDK, id: string, since: number) => {
|
||||
const filter: NDKFilter = {
|
||||
"#e": [id],
|
||||
kinds: [42],
|
||||
since: since,
|
||||
};
|
||||
const events = await ndk.fetchEvents(filter);
|
||||
const array = [...events];
|
||||
set({ messages: array });
|
||||
fetch: async (id: string) => {
|
||||
const events = await getChannelMessages(id);
|
||||
set({ messages: events });
|
||||
},
|
||||
add: (message: any) => {
|
||||
add: (id, event: LumeEvent) => {
|
||||
set((state: any) => {
|
||||
state.messages.push(message);
|
||||
createChannelMessage(
|
||||
id,
|
||||
event.id,
|
||||
event.pubkey,
|
||||
event.kind,
|
||||
event.content,
|
||||
event.tags,
|
||||
event.created_at,
|
||||
);
|
||||
state.messages.push({
|
||||
event_id: event.id,
|
||||
channel_id: id,
|
||||
hide: 0,
|
||||
mute: 0,
|
||||
...event,
|
||||
});
|
||||
});
|
||||
},
|
||||
openReply: (id: string, pubkey: string, content: string) => {
|
||||
|
@@ -4,8 +4,19 @@ import getUrls from "get-urls";
|
||||
import { parseReferences } from "nostr-tools";
|
||||
import reactStringReplace from "react-string-replace";
|
||||
|
||||
function isJsonString(str) {
|
||||
try {
|
||||
JSON.parse(str);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function parser(event: any) {
|
||||
event.tags = destr(event.tags);
|
||||
if (isJsonString(event.tags)) {
|
||||
event["tags"] = destr(event.tags);
|
||||
}
|
||||
|
||||
const references = parseReferences(event);
|
||||
const urls = getUrls(event.content);
|
||||
|
Reference in New Issue
Block a user