mirror of
https://github.com/aljazceru/landscape-template.git
synced 2025-12-17 06:14:27 +01:00
feat: more work on the commenting system
This commit is contained in:
@@ -139,7 +139,7 @@ export interface NexusGenObjects {
|
||||
PostComment: { // root type
|
||||
author: NexusGenRootTypes['Author']; // Author!
|
||||
body: string; // String!
|
||||
createdAt: NexusGenScalars['Date']; // Date!
|
||||
created_at: NexusGenScalars['Date']; // Date!
|
||||
id: number; // Int!
|
||||
parentId?: number | null; // Int
|
||||
votes_count: number; // Int!
|
||||
@@ -158,7 +158,6 @@ export interface NexusGenObjects {
|
||||
}
|
||||
Query: {};
|
||||
Question: { // root type
|
||||
answers_count: number; // Int!
|
||||
body: string; // String!
|
||||
createdAt: NexusGenScalars['Date']; // Date!
|
||||
excerpt: string; // String!
|
||||
@@ -316,7 +315,7 @@ export interface NexusGenFieldTypes {
|
||||
PostComment: { // field return type
|
||||
author: NexusGenRootTypes['Author']; // Author!
|
||||
body: string; // String!
|
||||
createdAt: NexusGenScalars['Date']; // Date!
|
||||
created_at: NexusGenScalars['Date']; // Date!
|
||||
id: number; // Int!
|
||||
parentId: number | null; // Int
|
||||
votes_count: number; // Int!
|
||||
@@ -358,10 +357,8 @@ export interface NexusGenFieldTypes {
|
||||
searchProjects: NexusGenRootTypes['Project'][]; // [Project!]!
|
||||
}
|
||||
Question: { // field return type
|
||||
answers_count: number; // Int!
|
||||
author: NexusGenRootTypes['Author']; // Author!
|
||||
body: string; // String!
|
||||
comments: NexusGenRootTypes['PostComment'][]; // [PostComment!]!
|
||||
createdAt: NexusGenScalars['Date']; // Date!
|
||||
excerpt: string; // String!
|
||||
id: number; // Int!
|
||||
@@ -375,8 +372,6 @@ export interface NexusGenFieldTypes {
|
||||
Story: { // field return type
|
||||
author: NexusGenRootTypes['Author']; // Author!
|
||||
body: string; // String!
|
||||
comments: NexusGenRootTypes['PostComment'][]; // [PostComment!]!
|
||||
comments_count: number; // Int!
|
||||
cover_image: string | null; // String
|
||||
createdAt: NexusGenScalars['Date']; // Date!
|
||||
excerpt: string; // String!
|
||||
@@ -524,7 +519,7 @@ export interface NexusGenFieldTypeNames {
|
||||
PostComment: { // field return type name
|
||||
author: 'Author'
|
||||
body: 'String'
|
||||
createdAt: 'Date'
|
||||
created_at: 'Date'
|
||||
id: 'Int'
|
||||
parentId: 'Int'
|
||||
votes_count: 'Int'
|
||||
@@ -566,10 +561,8 @@ export interface NexusGenFieldTypeNames {
|
||||
searchProjects: 'Project'
|
||||
}
|
||||
Question: { // field return type name
|
||||
answers_count: 'Int'
|
||||
author: 'Author'
|
||||
body: 'String'
|
||||
comments: 'PostComment'
|
||||
createdAt: 'Date'
|
||||
excerpt: 'String'
|
||||
id: 'Int'
|
||||
@@ -583,8 +576,6 @@ export interface NexusGenFieldTypeNames {
|
||||
Story: { // field return type name
|
||||
author: 'Author'
|
||||
body: 'String'
|
||||
comments: 'PostComment'
|
||||
comments_count: 'Int'
|
||||
cover_image: 'String'
|
||||
createdAt: 'Date'
|
||||
excerpt: 'String'
|
||||
|
||||
@@ -124,7 +124,7 @@ interface PostBase {
|
||||
type PostComment {
|
||||
author: Author!
|
||||
body: String!
|
||||
createdAt: Date!
|
||||
created_at: Date!
|
||||
id: Int!
|
||||
parentId: Int
|
||||
votes_count: Int!
|
||||
@@ -169,10 +169,8 @@ type Query {
|
||||
}
|
||||
|
||||
type Question implements PostBase {
|
||||
answers_count: Int!
|
||||
author: Author!
|
||||
body: String!
|
||||
comments: [PostComment!]!
|
||||
createdAt: Date!
|
||||
excerpt: String!
|
||||
id: Int!
|
||||
@@ -187,8 +185,6 @@ type Question implements PostBase {
|
||||
type Story implements PostBase {
|
||||
author: Author!
|
||||
body: String!
|
||||
comments: [PostComment!]!
|
||||
comments_count: Int!
|
||||
cover_image: String
|
||||
createdAt: Date!
|
||||
excerpt: String!
|
||||
|
||||
@@ -70,29 +70,29 @@ const Story = objectType({
|
||||
resolve: () => t.typeName
|
||||
});
|
||||
t.string('cover_image');
|
||||
t.nonNull.list.nonNull.field('comments', {
|
||||
type: "PostComment",
|
||||
resolve: (parent) => prisma.story.findUnique({ where: { id: parent.id } }).comments()
|
||||
});
|
||||
// t.nonNull.list.nonNull.field('comments', {
|
||||
// type: "PostComment",
|
||||
// resolve: (parent) => prisma.story.findUnique({ where: { id: parent.id } }).comments()
|
||||
// });
|
||||
t.nonNull.list.nonNull.field('tags', {
|
||||
type: "Tag",
|
||||
resolve: (parent) => prisma.story.findUnique({ where: { id: parent.id } }).tags()
|
||||
});
|
||||
t.nonNull.int('comments_count', {
|
||||
resolve: async (parent) => {
|
||||
const post = await prisma.story.findUnique({
|
||||
where: { id: parent.id },
|
||||
include: {
|
||||
_count: {
|
||||
select: {
|
||||
comments: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
return post._count.comments;
|
||||
}
|
||||
});
|
||||
// t.nonNull.int('comments_count', {
|
||||
// resolve: async (parent) => {
|
||||
// const post = await prisma.story.findUnique({
|
||||
// where: { id: parent.id },
|
||||
// include: {
|
||||
// _count: {
|
||||
// select: {
|
||||
// comments: true
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// return post._count.comments;
|
||||
// }
|
||||
// });
|
||||
t.nonNull.field('author', {
|
||||
type: "Author",
|
||||
resolve: (parent) =>
|
||||
@@ -170,13 +170,13 @@ const Question = objectType({
|
||||
resolve: (parent) => prisma.question.findUnique({ where: { id: parent.id } }).tags()
|
||||
});
|
||||
|
||||
t.nonNull.int('answers_count');
|
||||
t.nonNull.list.nonNull.field('comments', {
|
||||
type: "PostComment",
|
||||
resolve: (parent) => {
|
||||
return prisma.question.findUnique({ where: { id: parent.id } }).comments();
|
||||
}
|
||||
});
|
||||
// t.nonNull.int('answers_count');
|
||||
// t.nonNull.list.nonNull.field('comments', {
|
||||
// type: "PostComment",
|
||||
// resolve: (parent) => {
|
||||
// return prisma.question.findUnique({ where: { id: parent.id } }).comments();
|
||||
// }
|
||||
// });
|
||||
|
||||
t.nonNull.field('author', {
|
||||
type: "Author",
|
||||
@@ -191,7 +191,7 @@ const PostComment = objectType({
|
||||
name: 'PostComment',
|
||||
definition(t) {
|
||||
t.nonNull.int('id');
|
||||
t.nonNull.date('createdAt');
|
||||
t.nonNull.date('created_at');
|
||||
t.nonNull.string('body');
|
||||
t.nonNull.field('author', {
|
||||
type: "Author"
|
||||
|
||||
@@ -4,11 +4,12 @@ const { createExpressApp } = require('../../modules');
|
||||
const express = require('express');
|
||||
const extractKeyFromCookie = require('../../utils/extractKeyFromCookie');
|
||||
const { getUserByPubKey } = require('../../auth/utils/helperFuncs');
|
||||
const { generatePrivateKey, getPublicKey, signEvent: signNostrEvent } = require('nostr-tools');
|
||||
const { generatePrivateKey, getPublicKey, signEvent: signNostrEvent } = require('../../utils/nostr-tools');
|
||||
const { prisma } = require('../../prisma');
|
||||
|
||||
|
||||
const signEvent = async (req, res) => {
|
||||
console.log(req.body);
|
||||
try {
|
||||
const userPubKey = await extractKeyFromCookie(req.headers.cookie ?? req.headers.Cookie)
|
||||
const user = await getUserByPubKey(userPubKey);
|
||||
@@ -33,16 +34,18 @@ const signEvent = async (req, res) => {
|
||||
})
|
||||
}
|
||||
|
||||
const { content, tags } = req.body
|
||||
const { content, tags, kind = 1 } = req.body.event
|
||||
const event = {
|
||||
kind: 1,
|
||||
kind,
|
||||
pubkey,
|
||||
content,
|
||||
tags,
|
||||
created_at: Date.now(),
|
||||
}
|
||||
|
||||
event.sig = await signNostrEvent(event, prvkey)
|
||||
event.sig = await signNostrEvent(event, prvkey);
|
||||
|
||||
console.log(event);
|
||||
|
||||
return res
|
||||
.status(200)
|
||||
@@ -59,11 +62,11 @@ let app;
|
||||
|
||||
if (process.env.LOCAL) {
|
||||
app = createExpressApp()
|
||||
app.get('/sign-event', signEvent);
|
||||
app.post('/sign-event', signEvent);
|
||||
}
|
||||
else {
|
||||
const router = express.Router();
|
||||
router.get('/sign-event', signEvent)
|
||||
router.post('/sign-event', signEvent)
|
||||
app = createExpressApp(router)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
|
||||
const express = require('express');
|
||||
var cors = require('cors');
|
||||
const cors = require('cors');
|
||||
const cookieParser = require('cookie-parser');
|
||||
const bodyParser = require('body-parser')
|
||||
|
||||
|
||||
const createExpressApp = (router) => {
|
||||
|
||||
const app = express();
|
||||
const routerBasePath = process.env.LOCAL ? `/dev` : `/.netlify/functions`
|
||||
|
||||
// parse application/x-www-form-urlencoded
|
||||
app.use(bodyParser.urlencoded({ extended: false }))
|
||||
|
||||
// parse application/json
|
||||
app.use(bodyParser.json())
|
||||
|
||||
app.use(cookieParser());
|
||||
app.use(cors({
|
||||
origin: ['http://localhost:3000', 'https://studio.apollographql.com'],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
|
||||
module.exports = {
|
||||
CONSTS: require('./consts')
|
||||
CONSTS: require('./consts'),
|
||||
nostr_tools: require('./nostr-tools')
|
||||
}
|
||||
45
api/utils/nostr-tools.js
Normal file
45
api/utils/nostr-tools.js
Normal file
@@ -0,0 +1,45 @@
|
||||
// import * as secp256k1 from '@noble/secp256k1'
|
||||
// import { Buffer } from 'buffer'
|
||||
const secp256k1 = require('@noble/secp256k1');
|
||||
const crypto = require('crypto')
|
||||
|
||||
function generatePrivateKey() {
|
||||
return Buffer.from(secp256k1.utils.randomPrivateKey()).toString('hex')
|
||||
}
|
||||
|
||||
function getPublicKey(privateKey) {
|
||||
return Buffer.from(secp256k1.schnorr.getPublicKey(privateKey)).toString('hex')
|
||||
}
|
||||
|
||||
|
||||
function serializeEvent(evt) {
|
||||
return JSON.stringify([
|
||||
0,
|
||||
evt.pubkey,
|
||||
evt.created_at,
|
||||
evt.kind,
|
||||
evt.tags,
|
||||
evt.content
|
||||
])
|
||||
}
|
||||
|
||||
|
||||
function getEventHash(event) {
|
||||
let eventHash = crypto.createHash('sha256')
|
||||
.update(Buffer.from(serializeEvent(event)))
|
||||
.digest()
|
||||
return Buffer.from(eventHash).toString('hex')
|
||||
}
|
||||
|
||||
|
||||
async function signEvent(event, key) {
|
||||
return Buffer.from(
|
||||
await secp256k1.schnorr.sign(getEventHash(event), key)
|
||||
).toString('hex')
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
generatePrivateKey,
|
||||
getPublicKey,
|
||||
signEvent,
|
||||
}
|
||||
241
package-lock.json
generated
241
package-lock.json
generated
@@ -10,6 +10,7 @@
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.5.10",
|
||||
"@hookform/resolvers": "^2.8.8",
|
||||
"@noble/secp256k1": "^1.6.3",
|
||||
"@prisma/client": "^3.12.0",
|
||||
"@react-hookz/web": "^13.2.1",
|
||||
"@react-spring/web": "^9.4.4",
|
||||
@@ -84,8 +85,8 @@
|
||||
"react-tooltip": "^4.2.21",
|
||||
"react-topbar-progress-indicator": "^4.1.1",
|
||||
"remirror": "^1.0.77",
|
||||
"secp256k1": "^4.0.3",
|
||||
"serverless-http": "^3.0.1",
|
||||
"stream": "npm:stream-browserify",
|
||||
"turndown": "^7.1.1",
|
||||
"typescript": "^4.6.3",
|
||||
"web-vitals": "^2.1.4",
|
||||
@@ -123,6 +124,7 @@
|
||||
"msw": "^0.39.2",
|
||||
"netlify-cli": "^10.0.0",
|
||||
"postcss": "^8.4.12",
|
||||
"readable-stream": "^4.1.0",
|
||||
"serverless-offline": "^8.7.0",
|
||||
"tailwindcss": "^3.0.24",
|
||||
"webpack": "^5.72.0"
|
||||
@@ -17048,6 +17050,19 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/are-we-there-yet/node_modules/readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/arg": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.1.tgz",
|
||||
@@ -18233,6 +18248,19 @@
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/bl/node_modules/readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/bluebird": {
|
||||
"version": "3.7.2",
|
||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
|
||||
@@ -18578,6 +18606,20 @@
|
||||
"safe-buffer": "^5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/browserify-sign/node_modules/readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/browserify-sign/node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
@@ -25222,6 +25264,19 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/hash-base/node_modules/readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/hash-base/node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
@@ -55868,6 +55923,19 @@
|
||||
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-gyp/node_modules/readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/node-int64": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
||||
@@ -60797,16 +60865,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.1.0.tgz",
|
||||
"integrity": "sha512-sVisi3+P2lJ2t0BPbpK629j8wRW06yKGJUcaLAGXPAUhyUxVJm7VsCTit1PFgT4JHUDMrGNR+ZjSKpzGaRF3zw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
"abort-controller": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
@@ -63591,6 +63658,19 @@
|
||||
"wbuf": "^1.7.3"
|
||||
}
|
||||
},
|
||||
"node_modules/spdy-transport/node_modules/readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/split-string": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
|
||||
@@ -63907,6 +63987,16 @@
|
||||
"integrity": "sha512-CMtO2Uneg3SAz/d6fZ/6qbqqQHi2ynq6/KzMD/26gTkiEShCcpqFfTHgOxsE0egAq6SX3FmN4CeSqn8BzXQkJg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/stream": {
|
||||
"name": "stream-browserify",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz",
|
||||
"integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==",
|
||||
"dependencies": {
|
||||
"inherits": "~2.0.4",
|
||||
"readable-stream": "^3.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/stream-browserify": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
|
||||
@@ -63994,6 +64084,19 @@
|
||||
"integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/stream/node_modules/readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/strict-event-emitter": {
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.2.4.tgz",
|
||||
@@ -64666,6 +64769,19 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-stream/node_modules/readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/tar/node_modules/mkdirp": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||
@@ -80925,6 +81041,18 @@
|
||||
"requires": {
|
||||
"delegates": "^1.0.0",
|
||||
"readable-stream": "^3.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"arg": {
|
||||
@@ -81851,6 +81979,16 @@
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -82153,6 +82291,17 @@
|
||||
"safe-buffer": "^5.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
@@ -87282,6 +87431,16 @@
|
||||
"safe-buffer": "^5.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
@@ -110601,6 +110760,16 @@
|
||||
"gauge": "^4.0.3",
|
||||
"set-blocking": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -114164,13 +114333,12 @@
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.1.0.tgz",
|
||||
"integrity": "sha512-sVisi3+P2lJ2t0BPbpK629j8wRW06yKGJUcaLAGXPAUhyUxVJm7VsCTit1PFgT4JHUDMrGNR+ZjSKpzGaRF3zw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
"abort-controller": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"readdirp": {
|
||||
@@ -116356,6 +116524,18 @@
|
||||
"obuf": "^1.1.2",
|
||||
"readable-stream": "^3.0.6",
|
||||
"wbuf": "^1.7.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"split-string": {
|
||||
@@ -116620,6 +116800,27 @@
|
||||
"integrity": "sha512-CMtO2Uneg3SAz/d6fZ/6qbqqQHi2ynq6/KzMD/26gTkiEShCcpqFfTHgOxsE0egAq6SX3FmN4CeSqn8BzXQkJg==",
|
||||
"dev": true
|
||||
},
|
||||
"stream": {
|
||||
"version": "npm:stream-browserify@3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz",
|
||||
"integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==",
|
||||
"requires": {
|
||||
"inherits": "~2.0.4",
|
||||
"readable-stream": "^3.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"stream-browserify": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
|
||||
@@ -117231,6 +117432,18 @@
|
||||
"fs-constants": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"telejson": {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.5.10",
|
||||
"@hookform/resolvers": "^2.8.8",
|
||||
"@noble/secp256k1": "^1.6.3",
|
||||
"@prisma/client": "^3.12.0",
|
||||
"@react-hookz/web": "^13.2.1",
|
||||
"@react-spring/web": "^9.4.4",
|
||||
@@ -79,8 +80,8 @@
|
||||
"react-tooltip": "^4.2.21",
|
||||
"react-topbar-progress-indicator": "^4.1.1",
|
||||
"remirror": "^1.0.77",
|
||||
"secp256k1": "^4.0.3",
|
||||
"serverless-http": "^3.0.1",
|
||||
"stream": "npm:stream-browserify",
|
||||
"turndown": "^7.1.1",
|
||||
"typescript": "^4.6.3",
|
||||
"web-vitals": "^2.1.4",
|
||||
@@ -174,6 +175,7 @@
|
||||
"msw": "^0.39.2",
|
||||
"netlify-cli": "^10.0.0",
|
||||
"postcss": "^8.4.12",
|
||||
"readable-stream": "^4.1.0",
|
||||
"serverless-offline": "^8.7.0",
|
||||
"tailwindcss": "^3.0.24",
|
||||
"webpack": "^5.72.0"
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `createdAt` on the `PostComment` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "PostComment" DROP COLUMN "createdAt",
|
||||
ADD COLUMN "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
||||
@@ -156,7 +156,7 @@ model Question {
|
||||
model PostComment {
|
||||
id Int @id @default(autoincrement())
|
||||
body String
|
||||
createdAt DateTime @default(now())
|
||||
created_at DateTime @default(now())
|
||||
votes_count Int @default(0)
|
||||
|
||||
replies PostComment[] @relation("PostComment_Replies")
|
||||
|
||||
@@ -51,6 +51,9 @@ functions:
|
||||
sign-event:
|
||||
handler: api/functions/sign-event/sign-event.handler
|
||||
events:
|
||||
- http:
|
||||
path: sign-event
|
||||
method: get
|
||||
- http:
|
||||
path: sign-event
|
||||
method: post
|
||||
|
||||
@@ -26,10 +26,11 @@ interface Props {
|
||||
placeholder?: string;
|
||||
name?: string;
|
||||
autoFocus?: boolean
|
||||
onSubmit?: (comment: string) => void;
|
||||
}
|
||||
|
||||
|
||||
export default function AddComment({ initialContent, placeholder, name, autoFocus }: Props) {
|
||||
export default function AddComment({ initialContent, placeholder, name, autoFocus, onSubmit }: Props) {
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const linkExtension = useMemo(() => {
|
||||
@@ -85,8 +86,8 @@ export default function AddComment({ initialContent, placeholder, name, autoFocu
|
||||
|
||||
|
||||
const submitComment = () => {
|
||||
console.log(valueRef.current);
|
||||
manager.view.updateState(manager.createState({ content: manager.createEmptyDoc() }))
|
||||
onSubmit?.(valueRef.current);
|
||||
// manager.view.updateState(manager.createState({ content: manager.createEmptyDoc() }))
|
||||
}
|
||||
|
||||
|
||||
@@ -96,8 +97,8 @@ export default function AddComment({ initialContent, placeholder, name, autoFocu
|
||||
manager={manager}
|
||||
state={state}
|
||||
onChange={e => {
|
||||
const html = e.helpers.getHTML(e.state)
|
||||
valueRef.current = html;
|
||||
const md = e.helpers.getMarkdown(e.state)
|
||||
valueRef.current = md;
|
||||
onChange(e);
|
||||
}}
|
||||
autoFocus={autoFocus}
|
||||
|
||||
@@ -18,9 +18,10 @@ export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
comment: {
|
||||
...MOCK_DATA.generatePostComments(1)[0],
|
||||
created_at: Date.now(),
|
||||
replies: [
|
||||
{ ...MOCK_DATA.generatePostComments(1)[0], replies: [] },
|
||||
{ ...MOCK_DATA.generatePostComments(1)[0], replies: [] }
|
||||
{ ...MOCK_DATA.generatePostComments(1)[0], replies: [], created_at: Date.now() },
|
||||
{ ...MOCK_DATA.generatePostComments(1)[0], replies: [], created_at: Date.now() }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,17 +7,17 @@ import { CommentWithReplies } from "../types";
|
||||
|
||||
interface Props {
|
||||
comment: CommentWithReplies
|
||||
isRoot?: boolean;
|
||||
onClickedReply?: () => void
|
||||
}
|
||||
|
||||
export default function Comment({ comment, onClickedReply }: Props) {
|
||||
export default function Comment({ comment, isRoot, onClickedReply }: Props) {
|
||||
|
||||
const [replyOpen, setReplyOpen] = useState(false)
|
||||
const isRootComment = !comment.parentId;
|
||||
|
||||
|
||||
const clickReply = () => {
|
||||
if (isRootComment)
|
||||
if (isRoot)
|
||||
setReplyOpen(true);
|
||||
else
|
||||
onClickedReply?.()
|
||||
|
||||
@@ -16,9 +16,8 @@ const Template: ComponentStory<typeof CommentCard> = (args) => <div className="m
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
comment: {
|
||||
...MOCK_DATA.posts.stories[0].comments[0],
|
||||
}
|
||||
comment: MOCK_DATA.generatePostComments(1)[0]
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -12,12 +12,12 @@ interface Props {
|
||||
export default function CommentCard({ comment, onReply }: Props) {
|
||||
return (
|
||||
<div className="border rounded-12 p-24">
|
||||
<Header author={comment.author} date={comment.createdAt} />
|
||||
<Header author={comment.author} date={new Date(comment.created_at).toISOString()} />
|
||||
<p className="text-body4 mt-16">
|
||||
{comment.body}
|
||||
</p>
|
||||
<div className="flex gap-24 mt-16 items-center">
|
||||
<VotesCount count={comment.votes_count} />
|
||||
<VotesCount count={0} />
|
||||
<button
|
||||
className="text-gray-600 font-medium hover:bg-gray-100 py-8 px-12 rounded-8"
|
||||
onClick={onReply}
|
||||
|
||||
@@ -16,7 +16,6 @@ const Template: ComponentStory<typeof CommentsSection> = (args) => <div classNam
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
comments: MOCK_DATA.generatePostComments(15)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,44 +1,55 @@
|
||||
import React, { useEffect, useMemo } from 'react'
|
||||
import Comment from '../Comment/Comment'
|
||||
import React, { useEffect, useMemo, useState } from 'react'
|
||||
import CommentRoot from '../Comment/Comment'
|
||||
import AddComment from '../AddComment/AddComment'
|
||||
import { convertCommentsToTree } from '../helpers'
|
||||
import { Comment as IComment } from '../types'
|
||||
import { } from '../helpers'
|
||||
import { Comment, } from '../types'
|
||||
import { createWorkerFactory, useWorker } from '@shopify/react-web-worker'
|
||||
|
||||
import * as CommentsWorker from './comments.worker'
|
||||
import { Post_Type } from 'src/graphql'
|
||||
|
||||
const createWorker = createWorkerFactory(() => import('./comments.worker'));
|
||||
// const createWorker = createWorkerFactory(() => import('./comments.worker'));
|
||||
|
||||
|
||||
interface Props {
|
||||
comments: IComment[]
|
||||
}
|
||||
type: Post_Type,
|
||||
id: number | string
|
||||
};
|
||||
|
||||
export default function CommentsSection({ comments }: Props) {
|
||||
const worker = useWorker(createWorker);
|
||||
|
||||
export default function CommentsSection({ type, id }: Props) {
|
||||
// const worker = useWorker(createWorker);
|
||||
// const commentsTree = useMemo(() => convertCommentsToTree(comments), [comments])
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
// Note: in your actual app code, make sure to check if Home
|
||||
// is still mounted before setting state asynchronously!
|
||||
const webWorkerMessage = await worker.now('prefix');
|
||||
// worker
|
||||
// alert(webWorkerMessage);
|
||||
const [commentsTree, setCommentsTree] = useState<Comment[]>([])
|
||||
|
||||
// setMessage(webWorkerMessage);
|
||||
})();
|
||||
}, [worker])
|
||||
const filter = useMemo(() => `boltfun ${type}_comment ${id}` + (process.env.NODE_ENV === 'development' ? 'dev' : ""), [id, type])
|
||||
|
||||
useEffect(() => {
|
||||
CommentsWorker.connect();
|
||||
const unsub = CommentsWorker.sub(filter, (newComments) => {
|
||||
setCommentsTree(newComments)
|
||||
})
|
||||
|
||||
return () => {
|
||||
unsub();
|
||||
}
|
||||
}, [filter]);
|
||||
|
||||
const handleNewComment = (newComment: string) => {
|
||||
CommentsWorker.post(newComment, filter);
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className="border border-gray-200 rounded-10 p-32 bg-white">
|
||||
<h6 className="text-body2 font-bolder">Discussion ({comments.length})</h6>
|
||||
<h6 className="text-body2 font-bolder">Discussion</h6>
|
||||
<div className="mt-24">
|
||||
<AddComment placeholder='Leave a comment...' />
|
||||
<AddComment placeholder='Leave a comment...' onSubmit={handleNewComment} />
|
||||
</div>
|
||||
<div className='flex flex-col gap-16 mt-32'>
|
||||
{commentsTree.map(comment => <CommentRoot key={comment.id} comment={comment} />)}
|
||||
</div>
|
||||
{/* <div className='flex flex-col gap-16 mt-32'>
|
||||
{commentsTree.map(comment => <Comment key={comment.id} comment={comment} />)}
|
||||
</div> */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,27 @@
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
import { relayPool } from 'nostr-tools'
|
||||
import { generatePrivateKey, getPublicKey, relayPool } from 'nostr-tools'
|
||||
import { Nullable } from 'remirror';
|
||||
import { CONSTS } from 'src/utils';
|
||||
import { Comment } from '../types';
|
||||
import { mapPubkeysToUsers, } from './comment.server';
|
||||
|
||||
|
||||
const pool = relayPool()
|
||||
type Author = {
|
||||
id: number;
|
||||
name: string;
|
||||
avatar: string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const pool = relayPool();
|
||||
const globalKeys = {
|
||||
prvkey: '',
|
||||
pubkey: ''
|
||||
}
|
||||
|
||||
export function now(prefix: string) {
|
||||
const hell = window.localStorage.getItem('test');
|
||||
@@ -16,31 +31,38 @@ export function now(prefix: string) {
|
||||
|
||||
export function connect() {
|
||||
const RELAYS = [
|
||||
'wss://rsslay.fiatjaf.com',
|
||||
'wss://nostr-pub.wellorder.net',
|
||||
'wss://expensive-relay.fiatjaf.com',
|
||||
'wss://nostr.bitcoiner.social',
|
||||
'wss://relayer.fiatjaf.com',
|
||||
'wss://nostr.rocks'
|
||||
'wss://nostr.drss.io',
|
||||
'wss://nostr-relay.freeberty.net',
|
||||
'wss://nostr.unknown.place',
|
||||
'wss://nostr-relay.untethr.me',
|
||||
'wss://relay.damus.io'
|
||||
];
|
||||
RELAYS.forEach(url => {
|
||||
pool.addRelay(url, { read: true, write: true })
|
||||
})
|
||||
pool.onNotice((notice: string, relay: any) => {
|
||||
console.log(`${relay.url} says: ${notice}`)
|
||||
})
|
||||
};
|
||||
|
||||
const events: Record<string, Required<NostrEvent>> = {};
|
||||
|
||||
export function sub(filter: any) {
|
||||
export function sub(filter: string, cb: (data: Comment[]) => void) {
|
||||
|
||||
let sub = pool.sub({
|
||||
filter,
|
||||
cb: (event: Required<NostrEvent>) => {
|
||||
filter: {
|
||||
"#r": [filter]
|
||||
},
|
||||
cb: async (event: Required<NostrEvent>) => {
|
||||
//Got a new event
|
||||
console.log(event);
|
||||
|
||||
if (!event.id) return;
|
||||
|
||||
if (event.id in events) return
|
||||
events[event.id] = event
|
||||
eventsUpdated();
|
||||
const newComments = await constructTree();
|
||||
cb(newComments)
|
||||
|
||||
}
|
||||
});
|
||||
@@ -53,28 +75,55 @@ export function sub(filter: any) {
|
||||
|
||||
const getSignedEvents = async (event: any) => {
|
||||
const res = await fetch(CONSTS.apiEndpoint + '/sign-event', {
|
||||
method: "post",
|
||||
body: JSON.stringify({ event }),
|
||||
credentials: 'include'
|
||||
})
|
||||
const data = await res.json()
|
||||
return data.event;
|
||||
}
|
||||
|
||||
export async function post(data: string, filter: any) {
|
||||
function setKeys() {
|
||||
if (globalKeys.prvkey) return;
|
||||
|
||||
let privateKey = localStorage.getItem('nostrkey')
|
||||
if (!privateKey) {
|
||||
privateKey = generatePrivateKey()
|
||||
localStorage.setItem('nostrkey', privateKey)
|
||||
}
|
||||
pool.setPrivateKey(privateKey)
|
||||
const pubkey = getPublicKey(privateKey)
|
||||
globalKeys.prvkey = privateKey
|
||||
globalKeys.pubkey = pubkey;
|
||||
|
||||
}
|
||||
|
||||
export async function post(data: string, filter: string) {
|
||||
|
||||
// setKeys();
|
||||
let event: NostrEvent;
|
||||
try {
|
||||
event = await getSignedEvents({
|
||||
// pubkey: globalKeys.pubkey,
|
||||
// created_at: Math.round(Date.now() / 1000),
|
||||
kind: 1,
|
||||
tags: [['r', filter]],
|
||||
content: data
|
||||
}) as NostrEvent;
|
||||
console.log(event);
|
||||
return;
|
||||
} catch (error) {
|
||||
alert("Couldn't sign the object successfully...")
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
let event: NostrEvent = {
|
||||
created_at: Math.round(Date.now() / 1000),
|
||||
kind: 1,
|
||||
tags: filter,
|
||||
content: data
|
||||
};
|
||||
|
||||
event = await getSignedEvents(event);
|
||||
const publishTimeout = setTimeout(() => {
|
||||
alert(
|
||||
`failed to publish event ${event.id?.slice(0, 5)}… to any relay.`
|
||||
)
|
||||
}, 4000)
|
||||
`failed to publish comment to any relay.`
|
||||
);
|
||||
}, 5000)
|
||||
|
||||
pool.publish(event, (status: number, relay: string) => {
|
||||
switch (status) {
|
||||
@@ -102,27 +151,14 @@ function extractParentId(event: NostrEvent): Nullable<string> {
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function eventsUpdated() {
|
||||
export async function constructTree() {
|
||||
// This function is responsible for transforming the object shaped events into a tree of comments
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
|
||||
// Sort them chronologically from oldest to newest
|
||||
let sortedEvenets = Object.values(events).sort((a, b) => a.created_at - b.created_at);
|
||||
|
||||
type Author = {
|
||||
id: number;
|
||||
name: string;
|
||||
avatar: string;
|
||||
}
|
||||
|
||||
type Comment = {
|
||||
id: string,
|
||||
pubkey: string;
|
||||
author?: Author;
|
||||
content: any;
|
||||
created_at: number;
|
||||
replies: Comment[]
|
||||
}
|
||||
|
||||
// Extract the pubkeys used
|
||||
const pubkeysSet = new Set();
|
||||
@@ -138,13 +174,19 @@ export async function eventsUpdated() {
|
||||
const parentId = extractParentId(e);
|
||||
if (parentId) {
|
||||
eventsTree[parentId]?.replies.push({
|
||||
...e,
|
||||
id: e.id,
|
||||
body: e.content,
|
||||
created_at: e.created_at,
|
||||
pubkey: e.pubkey,
|
||||
author: pubkeyToUser[e.pubkey],
|
||||
replies: [],
|
||||
});
|
||||
} else {
|
||||
eventsTree[e.id] = ({
|
||||
...e,
|
||||
id: e.id,
|
||||
body: e.content,
|
||||
created_at: e.created_at,
|
||||
pubkey: e.pubkey,
|
||||
author: pubkeyToUser[e.pubkey],
|
||||
replies: [],
|
||||
});
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { Comment, CommentWithReplies } from "./types";
|
||||
|
||||
|
||||
export function convertCommentsToTree(comments: Comment[]) {
|
||||
let tree: Record<Comment['id'], CommentWithReplies> = {};
|
||||
// export function convertCommentsToTree(comments: Comment[]) {
|
||||
// let tree: Record<Comment['id'], CommentWithReplies> = {};
|
||||
|
||||
for (const comment of comments)
|
||||
tree[comment.id] = { ...comment, replies: [] }
|
||||
// for (const comment of comments)
|
||||
// tree[comment.id] = { ...comment, replies: [] }
|
||||
|
||||
for (const comment of Object.values(tree)) {
|
||||
if (comment.parentId)
|
||||
tree[comment.parentId].replies = [...tree[comment.parentId].replies, comment]
|
||||
}
|
||||
// for (const comment of Object.values(tree)) {
|
||||
// if (comment.parentId)
|
||||
// tree[comment.parentId].replies = [...tree[comment.parentId].replies, comment]
|
||||
// }
|
||||
|
||||
// TODO
|
||||
// Sort the comments according to date
|
||||
// // TODO
|
||||
// // Sort the comments according to date
|
||||
|
||||
return Object.values(tree).filter(node => !node.parentId);
|
||||
}
|
||||
// return Object.values(tree).filter(node => !node.parentId);
|
||||
// }
|
||||
@@ -2,12 +2,12 @@
|
||||
import { Author } from "src/features/Posts/types";
|
||||
|
||||
export interface Comment {
|
||||
id: number
|
||||
author: Author
|
||||
createdAt: string
|
||||
body: string
|
||||
votes_count: number
|
||||
parentId: number | null
|
||||
id: string | number,
|
||||
pubkey: string;
|
||||
author?: Pick<Author, 'id' | 'name' | 'avatar'>;
|
||||
body: any;
|
||||
created_at: number;
|
||||
replies: Comment[]
|
||||
}
|
||||
|
||||
export interface CommentWithReplies extends Comment {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Link } from 'react-router-dom';
|
||||
import { createRoute } from 'src/utils/routing';
|
||||
|
||||
interface Props {
|
||||
author: {
|
||||
author?: {
|
||||
id: number,
|
||||
name: string,
|
||||
avatar: string
|
||||
@@ -45,11 +45,15 @@ export default function Header({
|
||||
|
||||
return (
|
||||
<div className='flex gap-8'>
|
||||
<Link to={createRoute({ type: 'profile', id: props.author.id, username: props.author.name })}>
|
||||
<Avatar width={avatarSize[size]} src={props.author.avatar} />
|
||||
</Link>
|
||||
{props.author ?
|
||||
<Link to={createRoute({ type: 'profile', id: props.author.id, username: props.author.name })}>
|
||||
<Avatar width={avatarSize[size]} src={props.author.avatar} />
|
||||
</Link>
|
||||
:
|
||||
<></>
|
||||
}
|
||||
<div className='overflow-hidden'>
|
||||
<p className={`${nameSize[size]} text-black font-medium overflow-hidden text-ellipsis`}>{trimText(props.author.name, 30)}</p>
|
||||
<p className={`${nameSize[size]} text-black font-medium overflow-hidden text-ellipsis`}>{props.author ? trimText(props.author.name, 30) : "Anonymouse"}</p>
|
||||
<p className={`text-body6 text-gray-600`}>{dateToShow()}</p>
|
||||
</div>
|
||||
{/* {showTimeAgo && <p className={`${nameSize[size]} text-gray-500 ml-auto `}>
|
||||
|
||||
@@ -16,14 +16,13 @@ export type QuestionCardType = Pick<Question,
|
||||
| 'author'
|
||||
| 'excerpt'
|
||||
| 'votes_count'
|
||||
| "answers_count"
|
||||
> & {
|
||||
comments: Array<Pick<Question['comments'][number],
|
||||
| 'id'
|
||||
| 'author'
|
||||
| 'body'
|
||||
| 'createdAt'
|
||||
>>
|
||||
// comments: Array<Pick<Question['comments'][number],
|
||||
// | 'id'
|
||||
// | 'author'
|
||||
// | 'body'
|
||||
// | 'createdAt'
|
||||
// >>
|
||||
tags: Array<Pick<Tag, 'id' | "title">>
|
||||
};
|
||||
interface Props {
|
||||
@@ -54,24 +53,24 @@ export default function QuestionCard({ question }: Props) {
|
||||
<hr className="my-16 bg-gray-200" />
|
||||
<div className="flex gap-24 items-center">
|
||||
<VoteButton votes={question.votes_count} dense />
|
||||
<div className="text-gray-600">
|
||||
{/* <div className="text-gray-600">
|
||||
<FiUsers /> <span className="align-middle text-body5">{question.answers_count} Answers</span>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
|
||||
<div className="flex p-16 mt-16 flex-col gap-10 bg-gray-50">
|
||||
<div className="flex flex-col gap-10">
|
||||
{question.comments.slice(0, 2).map(comment => <div key={comment.id} className="border-b last-of-type:border-b-0 pb-8 " >
|
||||
{/* {question.comments.slice(0, 2).map(comment => <div key={comment.id} className="border-b last-of-type:border-b-0 pb-8 " >
|
||||
<Header author={comment.author} size='sm' date={comment.createdAt} />
|
||||
<p className="text-body5 text-gray-600 mt-8">{trimText(comment.body, 80)}</p>
|
||||
</div>)}
|
||||
</div>)} */}
|
||||
</div>
|
||||
|
||||
<div className="flex">
|
||||
{/* <div className="flex">
|
||||
<Link to={`/blog/post/Question/${question.id}`} className="text-black font-medium p-8 hover:bg-gray-100 rounded">
|
||||
See all {question.answers_count} comments
|
||||
</Link>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -18,7 +18,6 @@ export type StoryCardType = Pick<Story,
|
||||
| 'author'
|
||||
| 'excerpt'
|
||||
| 'votes_count'
|
||||
| 'comments_count'
|
||||
> & {
|
||||
tags: Array<Pick<Tag, 'id' | "title">>
|
||||
};
|
||||
@@ -51,9 +50,9 @@ export default function StoryCard({ story }: Props) {
|
||||
<hr className="my-16 bg-gray-200" />
|
||||
<div className="flex gap-24 items-center">
|
||||
<VoteButton votes={story.votes_count} dense onVote={vote} />
|
||||
<div className="text-gray-600">
|
||||
{/* <div className="text-gray-600">
|
||||
<BiComment /> <span className="align-middle text-body5">{story.comments_count} Comments</span>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@ mutation createStory($data: StoryInputType) {
|
||||
is_published
|
||||
type
|
||||
cover_image
|
||||
comments_count
|
||||
# comments_count
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ query Feed($take: Int, $skip: Int, $sortBy: String, $tag: Int) {
|
||||
votes_count
|
||||
type
|
||||
cover_image
|
||||
comments_count
|
||||
# comments_count
|
||||
}
|
||||
... on Bounty {
|
||||
id
|
||||
@@ -59,18 +59,18 @@ query Feed($take: Int, $skip: Int, $sortBy: String, $tag: Int) {
|
||||
}
|
||||
votes_count
|
||||
type
|
||||
answers_count
|
||||
comments {
|
||||
id
|
||||
createdAt
|
||||
body
|
||||
author {
|
||||
id
|
||||
name
|
||||
avatar
|
||||
join_date
|
||||
}
|
||||
}
|
||||
# answers_count
|
||||
# comments {
|
||||
# id
|
||||
# created_at
|
||||
# body
|
||||
# author {
|
||||
# id
|
||||
# name
|
||||
# avatar
|
||||
# join_date
|
||||
# }
|
||||
# }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Helmet } from 'react-helmet'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import LoadingPage from 'src/Components/LoadingPage/LoadingPage'
|
||||
import NotFoundPage from 'src/features/Shared/pages/NotFoundPage/NotFoundPage'
|
||||
import { usePostDetailsQuery } from 'src/graphql'
|
||||
import { Post_Type, usePostDetailsQuery } from 'src/graphql'
|
||||
import { capitalize } from 'src/utils/helperFunctions'
|
||||
import { useAppSelector, } from 'src/utils/hooks'
|
||||
import { CommentsSection } from '../../Components/Comments'
|
||||
@@ -72,7 +72,7 @@ export default function PostDetailsPage() {
|
||||
</div>
|
||||
</aside>
|
||||
<div id="comments">
|
||||
<CommentsSection comments={[]} />
|
||||
<CommentsSection id={post.id} type={type as Post_Type} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -19,19 +19,19 @@ query PostDetails($id: Int!, $type: POST_TYPE!) {
|
||||
type
|
||||
cover_image
|
||||
is_published
|
||||
comments_count
|
||||
comments {
|
||||
id
|
||||
createdAt
|
||||
body
|
||||
votes_count
|
||||
parentId
|
||||
author {
|
||||
id
|
||||
name
|
||||
avatar
|
||||
}
|
||||
}
|
||||
# comments_count
|
||||
# comments {
|
||||
# id
|
||||
# created_at
|
||||
# body
|
||||
# votes_count
|
||||
# parentId
|
||||
# author {
|
||||
# id
|
||||
# name
|
||||
# avatar
|
||||
# }
|
||||
# }
|
||||
}
|
||||
... on Bounty {
|
||||
id
|
||||
@@ -82,19 +82,19 @@ query PostDetails($id: Int!, $type: POST_TYPE!) {
|
||||
}
|
||||
votes_count
|
||||
type
|
||||
answers_count
|
||||
comments {
|
||||
id
|
||||
createdAt
|
||||
body
|
||||
votes_count
|
||||
parentId
|
||||
author {
|
||||
id
|
||||
name
|
||||
avatar
|
||||
}
|
||||
}
|
||||
# answers_count
|
||||
# comments {
|
||||
# id
|
||||
# created_at
|
||||
# body
|
||||
# votes_count
|
||||
# parentId
|
||||
# author {
|
||||
# id
|
||||
# name
|
||||
# avatar
|
||||
# }
|
||||
# }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ export type PostComment = {
|
||||
__typename?: 'PostComment';
|
||||
author: Author;
|
||||
body: Scalars['String'];
|
||||
createdAt: Scalars['Date'];
|
||||
created_at: Scalars['Date'];
|
||||
id: Scalars['Int'];
|
||||
parentId: Maybe<Scalars['Int']>;
|
||||
votes_count: Scalars['Int'];
|
||||
@@ -311,10 +311,8 @@ export type QuerySearchProjectsArgs = {
|
||||
|
||||
export type Question = PostBase & {
|
||||
__typename?: 'Question';
|
||||
answers_count: Scalars['Int'];
|
||||
author: Author;
|
||||
body: Scalars['String'];
|
||||
comments: Array<PostComment>;
|
||||
createdAt: Scalars['Date'];
|
||||
excerpt: Scalars['String'];
|
||||
id: Scalars['Int'];
|
||||
@@ -330,8 +328,6 @@ export type Story = PostBase & {
|
||||
__typename?: 'Story';
|
||||
author: Author;
|
||||
body: Scalars['String'];
|
||||
comments: Array<PostComment>;
|
||||
comments_count: Scalars['Int'];
|
||||
cover_image: Maybe<Scalars['String']>;
|
||||
createdAt: Scalars['Date'];
|
||||
excerpt: Scalars['String'];
|
||||
@@ -482,7 +478,7 @@ export type CreateStoryMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type CreateStoryMutation = { __typename?: 'Mutation', createStory: { __typename?: 'Story', id: number, title: string, createdAt: any, body: string, votes_count: number, is_published: boolean | null, type: string, cover_image: string | null, comments_count: number, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | null };
|
||||
export type CreateStoryMutation = { __typename?: 'Mutation', createStory: { __typename?: 'Story', id: number, title: string, createdAt: any, body: string, votes_count: number, is_published: boolean | null, type: string, cover_image: string | null, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | null };
|
||||
|
||||
export type DeleteStoryMutationVariables = Exact<{
|
||||
deleteStoryId: Scalars['Int'];
|
||||
@@ -504,7 +500,7 @@ export type FeedQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type FeedQuery = { __typename?: 'Query', getFeed: Array<{ __typename?: 'Bounty', id: number, title: string, createdAt: any, excerpt: string, votes_count: number, type: string, cover_image: string | null, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'Author', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Question', id: number, title: string, createdAt: any, excerpt: string, votes_count: number, type: string, answers_count: number, author: { __typename?: 'Author', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, comments: Array<{ __typename?: 'PostComment', id: number, createdAt: any, body: string, author: { __typename?: 'Author', id: number, name: string, avatar: string, join_date: any } }> } | { __typename?: 'Story', id: number, title: string, createdAt: any, excerpt: string, votes_count: number, type: string, cover_image: string | null, comments_count: number, author: { __typename?: 'Author', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> }> };
|
||||
export type FeedQuery = { __typename?: 'Query', getFeed: Array<{ __typename?: 'Bounty', id: number, title: string, createdAt: any, excerpt: string, votes_count: number, type: string, cover_image: string | null, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'Author', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Question', id: number, title: string, createdAt: any, excerpt: string, votes_count: number, type: string, author: { __typename?: 'Author', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Story', id: number, title: string, createdAt: any, excerpt: string, votes_count: number, type: string, cover_image: string | null, author: { __typename?: 'Author', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> }> };
|
||||
|
||||
export type PostDetailsQueryVariables = Exact<{
|
||||
id: Scalars['Int'];
|
||||
@@ -512,14 +508,14 @@ export type PostDetailsQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type PostDetailsQuery = { __typename?: 'Query', getPostById: { __typename?: 'Bounty', id: number, title: string, createdAt: any, body: string, votes_count: number, type: string, cover_image: string | null, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'Author', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, applications: Array<{ __typename?: 'BountyApplication', id: number, date: string, workplan: string, author: { __typename?: 'Author', id: number, name: string, avatar: string } }> } | { __typename?: 'Question', id: number, title: string, createdAt: any, body: string, votes_count: number, type: string, answers_count: number, author: { __typename?: 'Author', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, comments: Array<{ __typename?: 'PostComment', id: number, createdAt: any, body: string, votes_count: number, parentId: number | null, author: { __typename?: 'Author', id: number, name: string, avatar: string } }> } | { __typename?: 'Story', id: number, title: string, createdAt: any, body: string, votes_count: number, type: string, cover_image: string | null, is_published: boolean | null, comments_count: number, author: { __typename?: 'Author', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, comments: Array<{ __typename?: 'PostComment', id: number, createdAt: any, body: string, votes_count: number, parentId: number | null, author: { __typename?: 'Author', id: number, name: string, avatar: string } }> } };
|
||||
export type PostDetailsQuery = { __typename?: 'Query', getPostById: { __typename?: 'Bounty', id: number, title: string, createdAt: any, body: string, votes_count: number, type: string, cover_image: string | null, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'Author', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, applications: Array<{ __typename?: 'BountyApplication', id: number, date: string, workplan: string, author: { __typename?: 'Author', id: number, name: string, avatar: string } }> } | { __typename?: 'Question', id: number, title: string, createdAt: any, body: string, votes_count: number, type: string, author: { __typename?: 'Author', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Story', id: number, title: string, createdAt: any, body: string, votes_count: number, type: string, cover_image: string | null, is_published: boolean | null, author: { __typename?: 'Author', id: number, name: string, avatar: string, join_date: any }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } };
|
||||
|
||||
export type ProfileQueryVariables = Exact<{
|
||||
profileId: Scalars['Int'];
|
||||
}>;
|
||||
|
||||
|
||||
export type ProfileQuery = { __typename?: 'Query', profile: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any, role: string | null, email: string | null, jobTitle: string | null, lightning_address: string | null, website: string | null, twitter: string | null, github: string | null, linkedin: string | null, bio: string | null, location: string | null, stories: Array<{ __typename?: 'Story', id: number, title: string, createdAt: any, tags: Array<{ __typename?: 'Tag', title: string, icon: string | null, id: number }> }> } | null };
|
||||
export type ProfileQuery = { __typename?: 'Query', profile: { __typename?: 'User', id: number, name: string, avatar: string, join_date: any, role: string | null, email: string | null, jobTitle: string | null, lightning_address: string | null, website: string | null, twitter: string | null, github: string | null, linkedin: string | null, bio: string | null, location: string | null, stories: Array<{ __typename?: 'Story', id: number, title: string, createdAt: any, tags: Array<{ __typename?: 'Tag', id: number, title: string, icon: string | null }> }> } | null };
|
||||
|
||||
export type UpdateProfileAboutMutationVariables = Exact<{
|
||||
data: InputMaybe<UpdateProfileInput>;
|
||||
@@ -1005,7 +1001,6 @@ export const CreateStoryDocument = gql`
|
||||
is_published
|
||||
type
|
||||
cover_image
|
||||
comments_count
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -1125,7 +1120,6 @@ export const FeedDocument = gql`
|
||||
votes_count
|
||||
type
|
||||
cover_image
|
||||
comments_count
|
||||
}
|
||||
... on Bounty {
|
||||
id
|
||||
@@ -1166,18 +1160,6 @@ export const FeedDocument = gql`
|
||||
}
|
||||
votes_count
|
||||
type
|
||||
answers_count
|
||||
comments {
|
||||
id
|
||||
createdAt
|
||||
body
|
||||
author {
|
||||
id
|
||||
name
|
||||
avatar
|
||||
join_date
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1235,19 +1217,6 @@ export const PostDetailsDocument = gql`
|
||||
type
|
||||
cover_image
|
||||
is_published
|
||||
comments_count
|
||||
comments {
|
||||
id
|
||||
createdAt
|
||||
body
|
||||
votes_count
|
||||
parentId
|
||||
author {
|
||||
id
|
||||
name
|
||||
avatar
|
||||
}
|
||||
}
|
||||
}
|
||||
... on Bounty {
|
||||
id
|
||||
@@ -1298,19 +1267,6 @@ export const PostDetailsDocument = gql`
|
||||
}
|
||||
votes_count
|
||||
type
|
||||
answers_count
|
||||
comments {
|
||||
id
|
||||
createdAt
|
||||
body
|
||||
votes_count
|
||||
parentId
|
||||
author {
|
||||
id
|
||||
name
|
||||
avatar
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1366,9 +1322,9 @@ export const ProfileDocument = gql`
|
||||
title
|
||||
createdAt
|
||||
tags {
|
||||
id
|
||||
title
|
||||
icon
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ const getAuthor = () => ({
|
||||
join_date: getDate()
|
||||
})
|
||||
|
||||
export const generatePostComments = (cnt: number = 1): Story['comments'] => {
|
||||
export const generatePostComments = (cnt: number = 1) => {
|
||||
|
||||
let comments = [];
|
||||
const rootCommentsIds: any[] = []
|
||||
@@ -24,10 +24,12 @@ export const generatePostComments = (cnt: number = 1): Story['comments'] => {
|
||||
const comment = {
|
||||
id: i + 1,
|
||||
body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nisi, at ut sit id. Vulputate aliquet aliquam penatibus ac, et dictum est etiam. Sagittis odio dui sed viverra donec rutrum iaculis vitae morbi.",
|
||||
createdAt: getDate(),
|
||||
created_at: Date.now(),
|
||||
author: getAuthor(),
|
||||
votes_count: 123,
|
||||
parentId
|
||||
parentId,
|
||||
pubkey: '123',
|
||||
replies: [],
|
||||
}
|
||||
comments.push(comment);
|
||||
if (!parentId)
|
||||
@@ -85,14 +87,17 @@ export let posts = {
|
||||
title: 'Digital Editor, Mars Review of Books',
|
||||
body: postBody,
|
||||
cover_image: getCoverImage(),
|
||||
comments_count: 3,
|
||||
// comments_count: 3,
|
||||
createdAt: getDate(),
|
||||
updatedAt: getDate(),
|
||||
votes_count: 120,
|
||||
excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio libero accumsan...',
|
||||
type: "Story",
|
||||
tags: randomItems(3, ...tags),
|
||||
author: getAuthor(),
|
||||
comments: generatePostComments(3),
|
||||
// comments: generatePostComments(3),
|
||||
is_published: true,
|
||||
|
||||
|
||||
},
|
||||
{
|
||||
@@ -100,15 +105,16 @@ export let posts = {
|
||||
title: 'The End Is Nigh',
|
||||
body: postBody,
|
||||
cover_image: getCoverImage(),
|
||||
comments_count: 3,
|
||||
// comments_count: 3,
|
||||
createdAt: getDate(),
|
||||
updatedAt: getDate(),
|
||||
votes_count: 120,
|
||||
excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio libero accumsan...',
|
||||
type: "Story",
|
||||
tags: randomItems(3, ...tags),
|
||||
author: getAuthor(),
|
||||
comments: generatePostComments(3),
|
||||
|
||||
// comments: generatePostComments(3),
|
||||
is_published: true,
|
||||
},
|
||||
] as Story[],
|
||||
bounties: [
|
||||
@@ -153,32 +159,36 @@ export let posts = {
|
||||
id: 33,
|
||||
title: 'Digital Editor, Mars Review of Books',
|
||||
body: postBody,
|
||||
answers_count: 3,
|
||||
// answers_count: 3,
|
||||
createdAt: getDate(),
|
||||
updatedAt: getDate(),
|
||||
votes_count: 70,
|
||||
excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio libero accumsan...',
|
||||
tags: [
|
||||
{ id: 1, title: "lnurl" },
|
||||
{ id: 2, title: "webln" },
|
||||
{ id: 1, title: "lnurl", description: '', isOfficial: false, icon: '' },
|
||||
{ id: 2, title: "webln", description: '', isOfficial: false, icon: '' },
|
||||
],
|
||||
author: getAuthor(),
|
||||
comments: generatePostComments(3)
|
||||
// comments: generatePostComments(3),
|
||||
is_published: true,
|
||||
},
|
||||
{
|
||||
type: "Question",
|
||||
id: 33,
|
||||
title: 'What is a man but miserable pile of secrets?',
|
||||
body: postBody,
|
||||
answers_count: 3,
|
||||
// answers_count: 3,
|
||||
createdAt: getDate(),
|
||||
updatedAt: getDate(),
|
||||
votes_count: 70,
|
||||
excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio libero accumsan...',
|
||||
tags: [
|
||||
{ id: 1, title: "lnurl" },
|
||||
{ id: 2, title: "webln" },
|
||||
{ id: 1, title: "lnurl", description: '', isOfficial: false, icon: '' },
|
||||
{ id: 2, title: "webln", description: '', isOfficial: false, icon: '' },
|
||||
],
|
||||
author: getAuthor(),
|
||||
comments: generatePostComments(3)
|
||||
// comments: generatePostComments(3),
|
||||
is_published: true,
|
||||
},
|
||||
] as Question[]
|
||||
}
|
||||
|
||||
8
src/utils/types/nostr.d.ts
vendored
8
src/utils/types/nostr.d.ts
vendored
@@ -11,16 +11,16 @@ interface NostrEvent {
|
||||
|
||||
|
||||
declare module 'nostr-tools' {
|
||||
declare function generatePrivateKey(): void
|
||||
declare function generatePrivateKey(): string
|
||||
declare function relayConnect(): void
|
||||
declare function relayPool(): any
|
||||
declare function signEvent(event: NostrEvent, key: sting): string
|
||||
declare function validateEvent(): void
|
||||
declare function verifySignature(event: NostrEvent): bool
|
||||
declare function serializeEvent(): void
|
||||
declare function serializeEvent(): string
|
||||
declare function getEventHash(event: NostrEvent): string
|
||||
declare function getPublicKey(event: NostrEvent): boolean
|
||||
declare function getBlankEvent(): void
|
||||
declare function getPublicKey(prvKey: string): string
|
||||
declare function getBlankEvent(): NostrEvent
|
||||
declare function matchFilter(): void
|
||||
declare function matchFilters(): void
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
],
|
||||
"baseUrl": ".",
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
|
||||
Reference in New Issue
Block a user