aboutsummaryrefslogtreecommitdiff
path: root/vnext/src/ui
diff options
context:
space:
mode:
Diffstat (limited to 'vnext/src/ui')
-rw-r--r--vnext/src/ui/Chat.js7
-rw-r--r--vnext/src/ui/Comment.js5
-rw-r--r--vnext/src/ui/Contacts.js3
-rw-r--r--vnext/src/ui/Feeds.js31
-rw-r--r--vnext/src/ui/Header.js6
-rw-r--r--vnext/src/ui/Login.js12
-rw-r--r--vnext/src/ui/Message.js5
-rw-r--r--vnext/src/ui/PM.js7
-rw-r--r--vnext/src/ui/Post.js6
-rw-r--r--vnext/src/ui/Settings.js14
-rw-r--r--vnext/src/ui/Thread.js9
-rw-r--r--vnext/src/ui/Users.js1
-rw-r--r--vnext/src/ui/VisitorContext.js32
13 files changed, 94 insertions, 44 deletions
diff --git a/vnext/src/ui/Chat.js b/vnext/src/ui/Chat.js
index 5ecb9c0f..cdf3de1b 100644
--- a/vnext/src/ui/Chat.js
+++ b/vnext/src/ui/Chat.js
@@ -9,10 +9,10 @@ import UserInfo from './UserInfo';
import { getChat, pm } from '../api';
import './Chat.css';
+import { useVisitor } from './VisitorContext';
/**
* @typedef {Object} ChatProps
- * @property {import('../api').SecureUser} visitor
* @property {EventSource} connection
*/
@@ -21,11 +21,12 @@ import './Chat.css';
* @param {ChatProps} props
*/
export default function Chat(props) {
+ const [visitor] = useVisitor();
const [chats, setChats] = useState([]);
const params = useParams();
let loadChat = useCallback((uname) => {
- const { hash } = props.visitor;
+ const { hash } = visitor;
setChats([]);
if (hash && uname) {
getChat(uname)
@@ -33,7 +34,7 @@ export default function Chat(props) {
setChats(response.data);
});
}
- }, [props.visitor]);
+ }, []);
let onMessage = useCallback((json) => {
const msg = JSON.parse(json.data);
diff --git a/vnext/src/ui/Comment.js b/vnext/src/ui/Comment.js
index 756b3487..45c80187 100644
--- a/vnext/src/ui/Comment.js
+++ b/vnext/src/ui/Comment.js
@@ -9,6 +9,7 @@ import MessageInput from './MessageInput';
import { fetchUserUri } from '../api';
import { chatItemStyle } from './helpers/BubbleStyle';
import { format, embedUrls } from '../utils/embed';
+import { useVisitor } from './VisitorContext';
let isMounted;
@@ -16,16 +17,16 @@ let isMounted;
* @param {{
msg: import('../api').Message,
draft: string,
- visitor: import('../api').User,
active: number,
setActive: function,
onStartEditing: function,
postComment: function
}} props
*/
-export default function Comment({ msg, draft, visitor, active, setActive, onStartEditing, postComment }) {
+export default function Comment({ msg, draft, active, setActive, onStartEditing, postComment }) {
const embedRef = useRef();
const msgRef = useRef();
+ const [visitor] = useVisitor();
const [author, setAuthor] = useState(msg.user);
useEffect(() => {
if (msgRef.current) {
diff --git a/vnext/src/ui/Contacts.js b/vnext/src/ui/Contacts.js
index 2a727b82..0005da9a 100644
--- a/vnext/src/ui/Contacts.js
+++ b/vnext/src/ui/Contacts.js
@@ -6,6 +6,9 @@ import { getChats } from '../api';
import Contact from './Contact.js';
import { ChatSpinner } from './Spinner';
+/**
+ *
+ */
export default function Contacts(props) {
const [pms, setPms] = useState([]);
useEffect(() => {
diff --git a/vnext/src/ui/Feeds.js b/vnext/src/ui/Feeds.js
index 84319c28..75f1800d 100644
--- a/vnext/src/ui/Feeds.js
+++ b/vnext/src/ui/Feeds.js
@@ -10,6 +10,7 @@ import Spinner from './Spinner';
import UserInfo from './UserInfo';
import { getMessages } from '../api';
+import { useVisitor } from './VisitorContext';
/**
* @typedef {object} Query
@@ -21,12 +22,12 @@ import { getMessages } from '../api';
/**
* @typedef {object} PageProps
* @property {string=} search
- * @property {import('../api').SecureUser} visitor
* @property {import('../api').Message[]=} msgs
*/
-function RequireAuth({ visitor, children }) {
+function RequireAuth({ children }) {
let location = useLocation();
+ let [ visitor ] = useVisitor();
if (!visitor.hash) {
// Redirect them to the /login page, but save the current location they were
// trying to go to when they were redirected. This allows us to send them
@@ -41,7 +42,7 @@ function RequireAuth({ visitor, children }) {
/**
* @param {PageProps} props
*/
-export function Discover({ visitor }) {
+export function Discover() {
const location = useLocation();
let search = qs.parse(location.search.substring(1));
const query = {
@@ -49,24 +50,24 @@ export function Discover({ visitor }) {
search: search,
pageParam: search.search ? 'page' : 'before_mid'
};
- return (<Feed query={query} visitor={visitor} />);
+ return (<Feed query={query} />);
}
/**
* @param {PageProps} props
*/
-export function Discussions({ visitor }) {
+export function Discussions() {
const query = {
baseUrl: '/api/messages/discussions',
pageParam: 'to'
};
- return (<Feed query={query} visitor={visitor} />);
+ return (<Feed query={query} />);
}
/**
* @param {PageProps} props
*/
-export function Blog({ visitor }) {
+export function Blog() {
const { user } = useParams();
const location = useLocation();
const search = {
@@ -83,7 +84,7 @@ export function Blog({ visitor }) {
<div className="msg-cont">
<UserInfo uname={user} />
</div>
- <Feed query={query} visitor={visitor} />
+ <Feed query={query} />
</>
);
}
@@ -91,7 +92,7 @@ export function Blog({ visitor }) {
/**
* @param {PageProps} props
*/
-export function Tag({ visitor }) {
+export function Tag() {
const params = useParams();
const { tag } = params;
const query = {
@@ -101,27 +102,26 @@ export function Tag({ visitor }) {
},
pageParam: 'before_mid'
};
- return (<Feed query={query} visitor={visitor} />);
+ return (<Feed query={query} />);
}
/**
* @param {PageProps} props
*/
-export function Home({ visitor }) {
+export function Home() {
const query = {
baseUrl: '/api/home',
pageParam: 'before_mid'
};
return (
- <RequireAuth visitor={visitor}>
- <Feed query={query} visitor={visitor} />
+ <RequireAuth>
+ <Feed query={query} />
</RequireAuth>
);
}
/**
* @typedef {object} FeedState
- * @property { import('../api').SecureUser } visitor
* @property { import('../api').Message[]= } msgs
* @property { Query} query
*/
@@ -129,8 +129,9 @@ export function Home({ visitor }) {
/**
* @param {FeedState} props
*/
-function Feed({ visitor, query }) {
+function Feed({ query }) {
const location = useLocation();
+ const [visitor] = useVisitor();
const [state, setState] = useState({
hash: visitor.hash,
msgs: [],
diff --git a/vnext/src/ui/Header.js b/vnext/src/ui/Header.js
index 3162c9ea..db8959ea 100644
--- a/vnext/src/ui/Header.js
+++ b/vnext/src/ui/Header.js
@@ -4,8 +4,10 @@ import { Link, useNavigate } from 'react-router-dom';
import Icon from './Icon';
import { UserLink } from './UserInfo';
import SearchBox from './SearchBox';
+import { useVisitor } from './VisitorContext';
-function Header({ visitor, className }) {
+function Header() {
+ const [visitor] = useVisitor();
const navigate = useNavigate();
/**
* @param {string} searchString
@@ -17,7 +19,7 @@ function Header({ visitor, className }) {
navigate(location);
}, [navigate]);
return (
- <div id="header" className={className}>
+ <div id="header">
<div id="header_wrapper">
{
visitor.uid < 0 ?
diff --git a/vnext/src/ui/Login.js b/vnext/src/ui/Login.js
index 5a96c822..98f9328b 100644
--- a/vnext/src/ui/Login.js
+++ b/vnext/src/ui/Login.js
@@ -8,22 +8,22 @@ import { useForm } from 'react-hook-form';
import { me, facebookLink, vkLink, appleLink } from '../api';
import './Login.css';
+import { useVisitor } from './VisitorContext';
/**
- * @typedef {Object} LoginProps
- * @property {import('../api').SecureUser} visitor
- * @property {function} onAuth
+ * @typedef {object} LoginProps
+ * @property {Function} onAuth
*/
/**
* Login page
+ *
* @param {LoginProps} props
*/
-function Login({ visitor, onAuth }) {
-
+function Login({ onAuth }) {
const location = useLocation();
const navigate = useNavigate();
-
+ const [visitor] = useVisitor();
useEffect(() => {
if (visitor.hash) {
const {retpath } = location.state || '/';
diff --git a/vnext/src/ui/Message.js b/vnext/src/ui/Message.js
index dd6fc0ce..37d74312 100644
--- a/vnext/src/ui/Message.js
+++ b/vnext/src/ui/Message.js
@@ -8,11 +8,11 @@ import Avatar from './Avatar';
import { UserLink } from './UserInfo';
import { format, embedUrls } from '../utils/embed';
+import { useVisitor } from './VisitorContext';
/**
* @typedef {object} MessageProps
* @property { import('../client').Message } data data
- * @property { import('../client').SecureUser } visitor visitor
*/
/**
@@ -20,7 +20,8 @@ import { format, embedUrls } from '../utils/embed';
*
* @param {React.PropsWithChildren<{}> & MessageProps} props props
*/
-export default function Message({ visitor, data, children }) {
+export default function Message({ data, children }) {
+ const [visitor] = useVisitor();
const isCode = (data.tags || []).indexOf('code') >= 0;
const likesSummary = data.likes ? `${data.likes}` : 'Recommend';
const commentsSummary = data.replies ? `${data.replies}` : 'Comment';
diff --git a/vnext/src/ui/PM.js b/vnext/src/ui/PM.js
index 8885153d..d5a7eff1 100644
--- a/vnext/src/ui/PM.js
+++ b/vnext/src/ui/PM.js
@@ -3,9 +3,11 @@ import { memo } from 'react';
import Avatar from './Avatar';
import { format } from '../utils/embed';
import { chatItemStyle } from './helpers/BubbleStyle';
+import { useVisitor } from './VisitorContext';
function PM(props) {
- const { chat, visitor } = props;
+ const { chat } = props;
+ const [visitor] = useVisitor();
return (
<li>
<div style={chatItemStyle(visitor, chat)}>
@@ -21,7 +23,6 @@ function PM(props) {
export default memo(PM);
/*
PM.propTypes = {
- chat: MessageType.isRequired,
- visitor: UserType.isRequired
+ chat: MessageType.isRequired
};
*/
diff --git a/vnext/src/ui/Post.js b/vnext/src/ui/Post.js
index a1d14ea0..51c25a19 100644
--- a/vnext/src/ui/Post.js
+++ b/vnext/src/ui/Post.js
@@ -7,13 +7,15 @@ import Button from './Button';
import MessageInput from './MessageInput';
import { post, update } from '../api';
+import { useVisitor } from './VisitorContext';
/**
- * @param {{visitor: import('../api').User}} props
+ *
*/
-export default function Post({ visitor }) {
+export default function Post() {
const location = useLocation();
const navigate = useNavigate();
+ const [visitor] = useVisitor();
let draftMessage = (location.state || {}).draft || {};
let [draft, setDraft] = useState(draftMessage.body);
let params = qs.parse(window.location.search.substring(1));
diff --git a/vnext/src/ui/Settings.js b/vnext/src/ui/Settings.js
index ccafffa3..3ae33567 100644
--- a/vnext/src/ui/Settings.js
+++ b/vnext/src/ui/Settings.js
@@ -6,11 +6,13 @@ import Button from './Button';
import Icon from './Icon';
import UploadButton from './UploadButton';
import Avatar from './Avatar';
+import { useVisitor } from './VisitorContext';
/**
- * @param {{ visitor: import('../api').SecureUser, onChange: function }} props
+ * @param {{ onChange: Function }} props
*/
-function ChangeAvatarForm({ visitor, onChange }) {
+function ChangeAvatarForm({ onChange }) {
+ const [visitor] = useVisitor();
const [avatar, setAvatar] = useState('');
const [preview, setPreview] = useState();
const avatarInput = useRef();
@@ -53,9 +55,11 @@ function ChangeAvatarForm({ visitor, onChange }) {
}
/**
- * @param {{ visitor: import('../api').SecureUser, onChange: function }} props
+ * @param {{ onChange: Function }} props
*/
-export default function Settings({ visitor, onChange }) {
+export default function Settings({ onChange }) {
+
+ const [visitor] = useVisitor();
let passwordChanged = (event) => {
console.log('password changed');
@@ -100,7 +104,7 @@ export default function Settings({ visitor, onChange }) {
<div className="msg-cont">
<fieldset>
<legend><Icon name="ei-user" size="m" />Changing your avatar</legend>
- <ChangeAvatarForm visitor={visitor} onChange={onChange} />
+ <ChangeAvatarForm onChange={onChange} />
</fieldset>
<fieldset>
<legend><Icon name="ei-unlock" size="m" />Changing your password</legend>
diff --git a/vnext/src/ui/Thread.js b/vnext/src/ui/Thread.js
index 5c9412d6..b2d17824 100644
--- a/vnext/src/ui/Thread.js
+++ b/vnext/src/ui/Thread.js
@@ -7,6 +7,7 @@ import MessageInput from './MessageInput';
import Spinner from './Spinner';
import { getMessages, comment, update } from '../api';
+import { useVisitor } from './VisitorContext';
/**
* @type { import('../api').Message }
*/
@@ -14,7 +15,6 @@ const emptyMessage = {};
/**
* @param {{
- visitor: import('../api').SecureUser
connection: EventSource?
}} props
*/
@@ -27,7 +27,8 @@ export default function Thread(props) {
const [active, setActive] = useState(0);
const [editing, setEditing] = useState(emptyMessage);
- const [hash] = useState(props.visitor.hash);
+ const [visitor] = useVisitor();
+ const [hash] = useState(visitor.hash);
const { mid } = params;
let loadReplies = useCallback(() => {
@@ -97,7 +98,7 @@ export default function Thread(props) {
<>
{
message.mid ? (
- <Message data={message} visitor={props.visitor}>
+ <Message data={message}>
{active === (message.rid || 0) && <MessageInput data={message} text={editing.body || ''} onSend={postComment}>Write a comment...</MessageInput>}
</Message>
) : (
@@ -109,7 +110,7 @@ export default function Thread(props) {
{
!loading ? replies.map((msg) => (
<li id={msg.rid} key={msg.rid}>
- <Comment msg={msg} draft={msg.rid === editing.replyto ? editing.body : ''} visitor={props.visitor} active={active} setActive={setActive} onStartEditing={startEditing} postComment={postComment} />
+ <Comment msg={msg} draft={msg.rid === editing.replyto ? editing.body : ''} active={active} setActive={setActive} onStartEditing={startEditing} postComment={postComment} />
</li>
)) : (
<>
diff --git a/vnext/src/ui/Users.js b/vnext/src/ui/Users.js
index 2672c9cd..900cfaf0 100644
--- a/vnext/src/ui/Users.js
+++ b/vnext/src/ui/Users.js
@@ -22,6 +22,7 @@ export function Readers() {
/**
* UserInfo list component
+ *
* @param {{uname: string, prop: string}} props
*/
function Users({ uname, prop }) {
diff --git a/vnext/src/ui/VisitorContext.js b/vnext/src/ui/VisitorContext.js
new file mode 100644
index 00000000..8c5364e7
--- /dev/null
+++ b/vnext/src/ui/VisitorContext.js
@@ -0,0 +1,32 @@
+import { createContext, useContext, useState } from 'react';
+
+const Visitor = createContext();
+
+/** @type {import('../api').SecureUser} */
+const unknownUser = {
+ uid: -1
+};
+
+/**
+ * @param { import('react').PropsWithChildren<{}> } props
+ */
+export function VisitorProvider({ children }) {
+ const state = useState(unknownUser);
+ return <Visitor.Provider value={state}>{children}</Visitor.Provider>;
+}
+
+/**
+ * Visitor hook
+ *
+ * @returns {[
+ * import('../api').SecureUser,
+ * import('react').Dispatch<import('react').SetStateAction<import('../api').SecureUser>>
+ * ]} visitor hook
+ */
+export function useVisitor() {
+ const visitor = useContext(Visitor);
+ if (visitor === undefined) {
+ throw new Error('useVisitor must be used within a VisitorProvider');
+ }
+ return visitor;
+} \ No newline at end of file