Replies + Other changes
This commit is contained in:
parent
8aaa5103c4
commit
8b7ad119b0
@ -13,6 +13,7 @@
|
||||
"qr-code-styling": "^1.6.0-rc.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-modal": "^3.16.1",
|
||||
"react-redux": "^8.0.5",
|
||||
"react-router-dom": "^6.5.0",
|
||||
"react-scripts": "5.0.1",
|
||||
|
@ -8,7 +8,8 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import Event from "../nostr/Event";
|
||||
import ProfileImage from "./ProfileImage";
|
||||
import useEventPublisher from "../pages/feed/EventPublisher";
|
||||
import useEventPublisher from "../feed/EventPublisher";
|
||||
import { NoteCreator } from "./NoteCreator";
|
||||
|
||||
const UrlRegex = /((?:http|ftp|https):\/\/(?:[\w+?\.\w+])+(?:[a-zA-Z0-9\~\!\@\#\$\%\^\&\*\(\)_\-\=\+\\\/\?\.\:\;\'\,]*)?)/;
|
||||
const FileExtensionRegex = /\.([\w]+)$/;
|
||||
@ -21,6 +22,7 @@ export default function Note(props) {
|
||||
const reactions = props.reactions;
|
||||
const publisher = useEventPublisher();
|
||||
const [sig, setSig] = useState(false);
|
||||
const [showReply, setShowReply] = useState(false);
|
||||
const users = useSelector(s => s.users?.users);
|
||||
const ev = dataEvent ?? Event.FromObject(data);
|
||||
|
||||
@ -141,7 +143,7 @@ export default function Note(props) {
|
||||
{transformBody()}
|
||||
</div>
|
||||
<div className="footer">
|
||||
<span className="pill" onClick={() => {}}>
|
||||
<span className="pill" onClick={() => setShowReply(!showReply)}>
|
||||
<FontAwesomeIcon icon={faReply} />
|
||||
</span>
|
||||
<span className="pill" onClick={() => like()}>
|
||||
@ -152,6 +154,7 @@ export default function Note(props) {
|
||||
<FontAwesomeIcon icon={faInfo} />
|
||||
</span>
|
||||
</div>
|
||||
{showReply ? <NoteCreator replyTo={ev} onSend={() => setShowReply(false)}/> : null}
|
||||
</div>
|
||||
)
|
||||
}
|
32
src/element/NoteCreator.js
Normal file
32
src/element/NoteCreator.js
Normal file
@ -0,0 +1,32 @@
|
||||
import { useState } from "react";
|
||||
import useEventPublisher from "../feed/EventPublisher";
|
||||
|
||||
export function NoteCreator(props) {
|
||||
const replyTo = props.replyTo;
|
||||
const onSend = props.onSend;
|
||||
const publisher = useEventPublisher();
|
||||
const [note, setNote] = useState("");
|
||||
|
||||
async function sendNote() {
|
||||
let ev = replyTo ?
|
||||
await publisher.reply(replyTo, note)
|
||||
: await publisher.note(note);
|
||||
|
||||
console.debug("Sending note: ", ev);
|
||||
publisher.broadcast(ev);
|
||||
setNote("");
|
||||
if(typeof onSend === "function") {
|
||||
onSend();
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{replyTo ? <small>{`Reply to: ${replyTo.Id.substring(0, 8)}`}</small> : null}
|
||||
<div className="send-note">
|
||||
<input type="text" placeholder="Sup?" value={note} onChange={(e) => setNote(e.target.value)}></input>
|
||||
<div className="btn" onClick={() => sendNote()}>Send</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import "./ProfileImage.css";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import useProfile from "../pages/feed/ProfileFeed";
|
||||
import useProfile from "../feed/ProfileFeed";
|
||||
import Nostrich from "../nostrich.jpg";
|
||||
|
||||
export default function ProfileImage(props) {
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { useContext } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { NostrContext } from "../..";
|
||||
import Event from "../../nostr/Event";
|
||||
import EventKind from "../../nostr/EventKind";
|
||||
import Tag from "../../nostr/Tag";
|
||||
import { NostrContext } from "..";
|
||||
import Event from "../nostr/Event";
|
||||
import EventKind from "../nostr/EventKind";
|
||||
import Tag from "../nostr/Tag";
|
||||
|
||||
export default function useEventPublisher() {
|
||||
const system = useContext(NostrContext);
|
||||
@ -19,7 +19,7 @@ export default function useEventPublisher() {
|
||||
* @returns
|
||||
*/
|
||||
async function signEvent(ev, privKey) {
|
||||
if(nip07 === true && hasNip07) {
|
||||
if (nip07 === true && hasNip07) {
|
||||
ev.Id = await ev.CreateId();
|
||||
let tmpEv = await window.nostr.signEvent(ev.ToObject());
|
||||
console.log(tmpEv);
|
||||
@ -42,7 +42,7 @@ export default function useEventPublisher() {
|
||||
return await signEvent(ev, privKey);
|
||||
},
|
||||
note: async (msg) => {
|
||||
if(typeof msg !== "string") {
|
||||
if (typeof msg !== "string") {
|
||||
throw "Must be text!";
|
||||
}
|
||||
let ev = Event.ForPubKey(pubKey);
|
||||
@ -50,6 +50,38 @@ export default function useEventPublisher() {
|
||||
ev.Content = msg;
|
||||
return await signEvent(ev, privKey);
|
||||
},
|
||||
/**
|
||||
* Reply to a note
|
||||
* @param {Event} replyTo
|
||||
* @param {String} msg
|
||||
* @returns
|
||||
*/
|
||||
reply: async (replyTo, msg) => {
|
||||
if (typeof msg !== "string") {
|
||||
throw "Must be text!";
|
||||
}
|
||||
let ev = Event.ForPubKey(pubKey);
|
||||
ev.Kind = EventKind.TextNote;
|
||||
ev.Content = msg;
|
||||
|
||||
let thread = replyTo.GetThread();
|
||||
if (thread) {
|
||||
if (thread.Root) {
|
||||
ev.Tags.push(new Tag(["e", thread.Root.Event, "", "root"], ev.Tags.length));
|
||||
}
|
||||
if (thread.Reply) {
|
||||
ev.Tags.push(new Tag(["e", thread.Reply.Id, "", "reply"], ev.Tags.length));
|
||||
}
|
||||
ev.Tags.push(new Tag(["p", replyTo.PubKey], ev.Tags.length));
|
||||
for (let pk in thread.PubKeys) {
|
||||
ev.Tags.push(new Tag(["p", pk], ev.Tags.length));
|
||||
}
|
||||
} else {
|
||||
ev.Tags.push(new Tag(["e", replyTo.Id, "", "reply"], 0));
|
||||
ev.Tags.push(new Tag(["p", replyTo.PubKey], 1));
|
||||
}
|
||||
return await signEvent(ev, privKey);
|
||||
},
|
||||
like: async (evRef) => {
|
||||
let ev = Event.ForPubKey(pubKey);
|
||||
ev.Kind = EventKind.Reaction;
|
@ -1,10 +1,10 @@
|
||||
import { useContext, useEffect } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { NostrContext } from "../..";
|
||||
import Event from "../../nostr/Event";
|
||||
import EventKind from "../../nostr/EventKind";
|
||||
import { Subscriptions } from "../../nostr/Subscriptions";
|
||||
import { setFollows, setRelays } from "../../state/Login";
|
||||
import { NostrContext } from "..";
|
||||
import Event from "../nostr/Event";
|
||||
import EventKind from "../nostr/EventKind";
|
||||
import { Subscriptions } from "../nostr/Subscriptions";
|
||||
import { setFollows, setRelays } from "../state/Login";
|
||||
|
||||
/**
|
||||
* Managed loading data for the current logged in user
|
@ -1,7 +1,7 @@
|
||||
import { useContext, useEffect } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { NostrContext } from "../..";
|
||||
import { addPubKey } from "../../state/Users";
|
||||
import { NostrContext } from "..";
|
||||
import { addPubKey } from "../state/Users";
|
||||
|
||||
export default function useProfile(pubKey) {
|
||||
const dispatch = useDispatch();
|
@ -1,10 +1,10 @@
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { NostrContext } from "../..";
|
||||
import Event from "../../nostr/Event";
|
||||
import { Subscriptions } from "../../nostr/Subscriptions";
|
||||
import { addNote, reset } from "../../state/Thread";
|
||||
import { addPubKey } from "../../state/Users";
|
||||
import { NostrContext } from "..";
|
||||
import Event from "../nostr/Event";
|
||||
import { Subscriptions } from "../nostr/Subscriptions";
|
||||
import { addNote, reset } from "../state/Thread";
|
||||
import { addPubKey } from "../state/Users";
|
||||
|
||||
export default function useThreadFeed(id) {
|
||||
const dispatch = useDispatch();
|
@ -1,7 +1,7 @@
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { NostrContext } from "../../index";
|
||||
import EventKind from "../../nostr/EventKind";
|
||||
import { Subscriptions } from "../../nostr/Subscriptions";
|
||||
import { NostrContext } from "..";
|
||||
import EventKind from "../nostr/EventKind";
|
||||
import { Subscriptions } from "../nostr/Subscriptions";
|
||||
|
||||
export default function useTimelineFeed(pubKeys) {
|
||||
const system = useContext(NostrContext);
|
@ -1,10 +1,10 @@
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { NostrContext } from "../../index";
|
||||
import Event from "../../nostr/Event";
|
||||
import EventKind from "../../nostr/EventKind";
|
||||
import { Subscriptions } from "../../nostr/Subscriptions";
|
||||
import { setUserData } from "../../state/Users";
|
||||
import { NostrContext } from "..";
|
||||
import Event from "../nostr/Event";
|
||||
import EventKind from "../nostr/EventKind";
|
||||
import { Subscriptions } from "../nostr/Subscriptions";
|
||||
import { setUserData } from "../state/Users";
|
||||
|
||||
export default function useUsersCache() {
|
||||
const dispatch = useDispatch();
|
@ -71,6 +71,10 @@ input[type="text"], input[type="password"] {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.f-center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.f-grow {
|
||||
flex-grow: 1;
|
||||
}
|
||||
@ -112,4 +116,29 @@ div.form-group > div {
|
||||
|
||||
div.form-group > div:first-child {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.modal {
|
||||
position: absolute;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: rgba(0,0,0,0.8);
|
||||
}
|
||||
|
||||
.modal .modal-content {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.modal .modal-content > div {
|
||||
padding: 10px;
|
||||
border-radius: 10px;
|
||||
background-color: #333;
|
||||
margin-top: 5vh;
|
||||
}
|
||||
|
||||
.ReactModal__Body--open {
|
||||
overflow: hidden;
|
||||
}
|
@ -29,7 +29,7 @@ root.render(
|
||||
<Router>
|
||||
<Layout>
|
||||
<Routes>
|
||||
<Route path="/" exact element={<RootPage />} />
|
||||
<Route path="/" exact element={<RootPage/>} />
|
||||
<Route path="/login" exact element={<LoginPage />} />
|
||||
<Route path="/e/:id" exact element={<EventPage />} />
|
||||
<Route path="/p/:id" exact element={<ProfilePage />} />
|
||||
|
@ -128,7 +128,6 @@ export default class Connection {
|
||||
return;
|
||||
}
|
||||
let json = JSON.stringify(obj);
|
||||
console.debug(`[${this.Address}] >> ${json}`);
|
||||
this.Socket.send(json);
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,6 @@ export default class Thread {
|
||||
ret.Mentions = eTags.filter(a => a.Marker === "mention");
|
||||
}
|
||||
ret.PubKeys = ev.Tags.filter(a => a.Key === "p").map(a => a.PubKey);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { useParams } from "react-router-dom";
|
||||
import Thread from "../element/Thread";
|
||||
import useThreadFeed from "./feed/ThreadFeed";
|
||||
import useThreadFeed from "../feed/ThreadFeed";
|
||||
|
||||
export default function EventPage() {
|
||||
const params = useParams();
|
||||
|
@ -7,8 +7,8 @@ import { faBell } from "@fortawesome/free-solid-svg-icons";
|
||||
import { NostrContext } from ".."
|
||||
import ProfileImage from "../element/ProfileImage";
|
||||
import { init } from "../state/Login";
|
||||
import useLoginFeed from "./feed/LoginFeed";
|
||||
import useUsersCache from "./feed/UsersFeed";
|
||||
import useLoginFeed from "../feed/LoginFeed";
|
||||
import useUsersCache from "../feed/UsersFeed";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
export default function Layout(props) {
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { setPrivateKey, setNip07PubKey } from "../state/Login";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import * as secp from '@noble/secp256k1';
|
||||
import { bech32 } from "bech32";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
import { setPrivateKey, setNip07PubKey } from "../state/Login";
|
||||
|
||||
export default function LoginPage() {
|
||||
const dispatch = useDispatch();
|
||||
|
@ -8,10 +8,11 @@
|
||||
}
|
||||
|
||||
.profile .avatar {
|
||||
width: 128px;
|
||||
height: 128px;
|
||||
width: 256px;
|
||||
height: 256px;
|
||||
background-size: contain;
|
||||
cursor: pointer;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.profile .avatar .edit {
|
||||
|
@ -1,16 +1,19 @@
|
||||
import "./ProfilePage.css";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { useParams } from "react-router-dom";
|
||||
import useProfile from "./feed/ProfileFeed";
|
||||
import { useEffect, useState } from "react";
|
||||
import { resetProfile } from "../state/Users";
|
||||
import Nostrich from "../nostrich.jpg";
|
||||
import useEventPublisher from "./feed/EventPublisher";
|
||||
import useTimelineFeed from "./feed/TimelineFeed";
|
||||
import Note from "../element/Note";
|
||||
import { bech32 } from "bech32";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faQrcode } from "@fortawesome/free-solid-svg-icons";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
import useProfile from "../feed/ProfileFeed";
|
||||
import { resetProfile } from "../state/Users";
|
||||
import Nostrich from "../nostrich.jpg";
|
||||
import useEventPublisher from "../feed/EventPublisher";
|
||||
import useTimelineFeed from "../feed/TimelineFeed";
|
||||
import Note from "../element/Note";
|
||||
import QRCodeStyling from "qr-code-styling";
|
||||
import ReactModal from "react-modal";
|
||||
|
||||
export default function ProfilePage() {
|
||||
const dispatch = useDispatch();
|
||||
@ -21,13 +24,15 @@ export default function ProfilePage() {
|
||||
const { notes } = useTimelineFeed([id]);
|
||||
const loginPubKey = useSelector(s => s.login.publicKey);
|
||||
const isMe = loginPubKey === id;
|
||||
const qrRef = useRef();
|
||||
|
||||
let [name, setName] = useState("");
|
||||
let [picture, setPicture] = useState("");
|
||||
let [about, setAbout] = useState("");
|
||||
let [website, setWebsite] = useState("");
|
||||
let [nip05, setNip05] = useState("");
|
||||
let [lud16, setLud16] = useState("");
|
||||
const [name, setName] = useState("");
|
||||
const [picture, setPicture] = useState("");
|
||||
const [about, setAbout] = useState("");
|
||||
const [website, setWebsite] = useState("");
|
||||
const [nip05, setNip05] = useState("");
|
||||
const [lud16, setLud16] = useState("");
|
||||
const [showLnQr, setShowLnQr] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (user) {
|
||||
@ -57,6 +62,17 @@ export default function ProfilePage() {
|
||||
}
|
||||
}, [lud16]);
|
||||
|
||||
useEffect(() => {
|
||||
if (qrRef.current && showLnQr) {
|
||||
let qr = new QRCodeStyling({
|
||||
data: "",
|
||||
type: "canvas"
|
||||
});
|
||||
qrRef.current.innerHTML = "";
|
||||
qr.append(qrRef.current);
|
||||
}
|
||||
}, [showLnQr]);
|
||||
|
||||
async function saveProfile() {
|
||||
let ev = await publisher.metadata({
|
||||
name,
|
||||
@ -117,42 +133,19 @@ export default function ProfilePage() {
|
||||
function details() {
|
||||
return (
|
||||
<>
|
||||
<div className="form-group">
|
||||
<div>Name:</div>
|
||||
<div>
|
||||
{name}
|
||||
<h2>{name}</h2>
|
||||
<p>{about}</p>
|
||||
{website ? <a href={website} target="_blank" rel="noreferrer">{website}</a> : null}
|
||||
{lud16 ? <div className="flex f-center">
|
||||
<div className="btn" onClick={(e) => setShowLnQr(true)}>
|
||||
<FontAwesomeIcon icon={faQrcode} size="xl" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<div>About:</div>
|
||||
<div>
|
||||
{about}
|
||||
</div>
|
||||
</div>
|
||||
{website ?
|
||||
<div className="form-group">
|
||||
<div>Website:</div>
|
||||
<div>
|
||||
{website}
|
||||
</div>
|
||||
</div> : null}
|
||||
{nip05 ?
|
||||
<div className="form-group">
|
||||
<div>NIP-05:</div>
|
||||
<div>
|
||||
{nip05}
|
||||
</div>
|
||||
</div> : null}
|
||||
{lud16 ?
|
||||
<div className="form-group">
|
||||
<div>LN Address:</div>
|
||||
<div>
|
||||
{lud16}
|
||||
<div className="btn btn-sm" onClick={() => { }}>
|
||||
<FontAwesomeIcon icon={faQrcode} size="lg" />
|
||||
</div>
|
||||
</div>
|
||||
</div> : null}
|
||||
<div> ⚡️ {lud16}</div>
|
||||
</div> : null}
|
||||
{showLnQr === true ?
|
||||
<ReactModal isOpen={showLnQr} onRequestClose={() => setShowLnQr(false)} overlayClassName="modal" className="modal-content" preventScroll={true}>
|
||||
<div ref={qrRef}>QR</div>
|
||||
</ReactModal> : null}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -160,19 +153,22 @@ export default function ProfilePage() {
|
||||
return (
|
||||
<>
|
||||
<div className="profile">
|
||||
<div style={{ backgroundImage: `url(${picture})` }} className="avatar">
|
||||
{isMe ?
|
||||
<div className="edit">
|
||||
<div>Edit</div>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
<div>
|
||||
<div style={{ backgroundImage: `url(${picture})` }} className="avatar">
|
||||
{isMe ?
|
||||
<div className="edit">
|
||||
<div>Edit</div>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{isMe ? editor() : details()}
|
||||
</div>
|
||||
</div>
|
||||
<h4>Notes</h4>
|
||||
<br />
|
||||
<div className="btn">Notes</div>
|
||||
{notes?.sort((a, b) => b.created_at - a.created_at).map(a => <Note key={a.id} data={a} />)}
|
||||
</>
|
||||
)
|
||||
|
@ -1,36 +1,31 @@
|
||||
import "./Root.css";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useState } from "react";
|
||||
import Timeline from "./Timeline";
|
||||
import useEventPublisher from "./feed/EventPublisher";
|
||||
import Note from "../element/Note";
|
||||
import useTimelineFeed from "../feed/TimelineFeed";
|
||||
import { NoteCreator } from "../element/NoteCreator";
|
||||
|
||||
export default function RootPage() {
|
||||
const publisher = useEventPublisher();
|
||||
const pubKey = useSelector(s => s.login.publicKey);
|
||||
const follows = useSelector(a => a.login.follows)
|
||||
const { notes } = useTimelineFeed(follows);
|
||||
|
||||
const [note, setNote] = useState("");
|
||||
|
||||
async function sendNote() {
|
||||
let ev = await publisher.note(note);
|
||||
|
||||
console.debug("Sending note: ", ev);
|
||||
publisher.broadcast(ev);
|
||||
setNote("");
|
||||
}
|
||||
|
||||
function noteSigner() {
|
||||
return (
|
||||
<div className="send-note">
|
||||
<input type="text" placeholder="Sup?" value={note} onChange={(e) => setNote(e.target.value)}></input>
|
||||
<div className="btn" onClick={() => sendNote()}>Send</div>
|
||||
</div>
|
||||
);
|
||||
function followHints() {
|
||||
if (follows?.length === 0 && pubKey) {
|
||||
return (
|
||||
<>
|
||||
<h3>Hmm you're not following anybody?</h3>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{pubKey ? noteSigner() : null}
|
||||
<Timeline></Timeline>
|
||||
{pubKey ? <NoteCreator /> : null}
|
||||
{followHints()}
|
||||
<div className="timeline">
|
||||
{notes?.sort((a, b) => b.created_at - a.created_at).map(e => <Note key={e.id} data={e} />)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import { useSelector } from "react-redux";
|
||||
import Note from "../element/Note";
|
||||
import useTimelineFeed from "./feed/TimelineFeed";
|
||||
|
||||
export default function Timeline() {
|
||||
const follows = useSelector(a => a.login.follows)
|
||||
const { notes } = useTimelineFeed(follows);
|
||||
|
||||
return (
|
||||
<div className="timeline">
|
||||
{notes?.sort((a, b) => b.created_at - a.created_at).map(e => <Note key={e.id} data={e} />)}
|
||||
</div>
|
||||
);
|
||||
}
|
@ -2,6 +2,7 @@ import { createSlice } from '@reduxjs/toolkit'
|
||||
import * as secp from '@noble/secp256k1';
|
||||
|
||||
const PrivateKeyItem = "secret";
|
||||
const Nip07PublicKeyItem = "nip07:pubkey";
|
||||
|
||||
const LoginSlice = createSlice({
|
||||
name: "Login",
|
||||
@ -35,6 +36,7 @@ const LoginSlice = createSlice({
|
||||
init: (state) => {
|
||||
state.privateKey = window.localStorage.getItem(PrivateKeyItem);
|
||||
if (state.privateKey) {
|
||||
window.localStorage.removeItem(Nip07PublicKeyItem); // reset nip07 if using private key
|
||||
state.publicKey = secp.utils.bytesToHex(secp.schnorr.getPublicKey(state.privateKey, true));
|
||||
}
|
||||
state.relays = {
|
||||
@ -43,6 +45,13 @@ const LoginSlice = createSlice({
|
||||
"wss://relay.damus.io": { read: true, write: true },
|
||||
"wss://nostr-pub.wellorder.net": { read: true, write: true }
|
||||
};
|
||||
|
||||
// check nip07 pub key
|
||||
let nip07PubKey = window.localStorage.getItem(Nip07PublicKeyItem);
|
||||
if(nip07PubKey && !state.privateKey) {
|
||||
state.publicKey = nip07PubKey;
|
||||
state.nip07 = true;
|
||||
}
|
||||
},
|
||||
setPrivateKey: (state, action) => {
|
||||
state.privateKey = action.payload;
|
||||
@ -53,6 +62,7 @@ const LoginSlice = createSlice({
|
||||
state.publicKey = action.payload;
|
||||
},
|
||||
setNip07PubKey: (state, action) => {
|
||||
window.localStorage.setItem(Nip07PublicKeyItem, action.payload);
|
||||
state.publicKey = action.payload;
|
||||
state.nip07 = true;
|
||||
},
|
||||
|
@ -40,7 +40,7 @@ const UsersSlice = createSlice({
|
||||
if (!Array.isArray(ud)) {
|
||||
ud = [ud];
|
||||
}
|
||||
console.debug("Set user profiles: ", ud);
|
||||
|
||||
for (let x of ud) {
|
||||
let existing = state.users[x.pubkey];
|
||||
if (existing) {
|
||||
|
31
yarn.lock
31
yarn.lock
@ -4124,6 +4124,11 @@ execa@^5.0.0:
|
||||
signal-exit "^3.0.3"
|
||||
strip-final-newline "^2.0.0"
|
||||
|
||||
exenv@^1.2.0:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
|
||||
integrity sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==
|
||||
|
||||
exit@^0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
|
||||
@ -5838,7 +5843,7 @@ lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||
|
||||
loose-envify@^1.1.0, loose-envify@^1.4.0:
|
||||
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||
@ -7030,7 +7035,7 @@ prompts@^2.0.1, prompts@^2.4.2:
|
||||
kleur "^3.0.3"
|
||||
sisteransi "^1.0.5"
|
||||
|
||||
prop-types@^15.8.1:
|
||||
prop-types@^15.7.2, prop-types@^15.8.1:
|
||||
version "15.8.1"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
||||
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||
@ -7195,6 +7200,21 @@ react-is@^18.0.0:
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
|
||||
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
|
||||
|
||||
react-lifecycles-compat@^3.0.0:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
|
||||
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
|
||||
|
||||
react-modal@^3.16.1:
|
||||
version "3.16.1"
|
||||
resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.16.1.tgz#34018528fc206561b1a5467fc3beeaddafb39b2b"
|
||||
integrity sha512-VStHgI3BVcGo7OXczvnJN7yT2TWHJPDXZWyI/a0ssFNhGZWsPmB8cF0z33ewDXq4VfYMO1vXgiv/g8Nj9NDyWg==
|
||||
dependencies:
|
||||
exenv "^1.2.0"
|
||||
prop-types "^15.7.2"
|
||||
react-lifecycles-compat "^3.0.0"
|
||||
warning "^4.0.3"
|
||||
|
||||
react-redux@^8.0.5:
|
||||
version "8.0.5"
|
||||
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.0.5.tgz#e5fb8331993a019b8aaf2e167a93d10af469c7bd"
|
||||
@ -8491,6 +8511,13 @@ walker@^1.0.7:
|
||||
dependencies:
|
||||
makeerror "1.0.12"
|
||||
|
||||
warning@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
|
||||
integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
|
||||
dependencies:
|
||||
loose-envify "^1.0.0"
|
||||
|
||||
watchpack@^2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"
|
||||
|
Loading…
x
Reference in New Issue
Block a user