From f557f7b7c3cc869c7509da420ce392ba49f2c32f Mon Sep 17 00:00:00 2001 From: ADAMJR Date: Thu, 12 Aug 2021 15:56:19 +0100 Subject: [PATCH] It Works Now? --- backend/src/rest/apply-routes.ts | 1 - .../navigation/sidebar/sidebar-icons.tsx | 2 +- frontend/src/components/pages/guild-page.tsx | 4 +- .../src/components/pages/loading-page.tsx | 15 +++++++- .../src/components/pages/page-wrapper.tsx | 1 - .../src/components/routing/private-route.tsx | 20 +++------- frontend/src/store/guilds.ts | 37 ++++++++++--------- frontend/src/store/users.ts | 22 ++++++----- types/store.d.ts | 10 ++++- 9 files changed, 62 insertions(+), 50 deletions(-) diff --git a/backend/src/rest/apply-routes.ts b/backend/src/rest/apply-routes.ts index 4cc4dda..e89a54f 100644 --- a/backend/src/rest/apply-routes.ts +++ b/backend/src/rest/apply-routes.ts @@ -20,7 +20,6 @@ export default (app: Express) => { res.json(messages); }); - /* user.guilds: + can be populated easily to get user guilds - extra baggage diff --git a/frontend/src/components/navigation/sidebar/sidebar-icons.tsx b/frontend/src/components/navigation/sidebar/sidebar-icons.tsx index 9fdb1be..bd30b1d 100644 --- a/frontend/src/components/navigation/sidebar/sidebar-icons.tsx +++ b/frontend/src/components/navigation/sidebar/sidebar-icons.tsx @@ -9,7 +9,7 @@ import GuildMenu from '../../ctx-menus/guild-menu'; const SidebarIcons: React.FunctionComponent = () => { const dispatch = useDispatch(); const user = useSelector((s: Store.AppStore) => s.auth.user)!; - const guilds = useSelector((s: Store.AppStore) => s.entities.guilds)!; + const { list: guilds } = useSelector((s: Store.AppStore) => s.entities.guilds)!; const guildIcons = guilds.map(g => ( diff --git a/frontend/src/components/pages/guild-page.tsx b/frontend/src/components/pages/guild-page.tsx index 5bfbe5e..927a7a6 100644 --- a/frontend/src/components/pages/guild-page.tsx +++ b/frontend/src/components/pages/guild-page.tsx @@ -13,7 +13,6 @@ const GuildPage: React.FunctionComponent = () => { const { channelId, guildId }: any = useParams(); const dispatch = useDispatch(); const ui = useSelector((s: Store.AppStore) => s.ui); - const guilds = useSelector((s: Store.AppStore) => s.entities.guilds); const guild = useSelector(getGuild(guildId)); const channel = useSelector(getChannel(guildId, channelId)); @@ -21,9 +20,8 @@ const GuildPage: React.FunctionComponent = () => { dispatch(pageSwitched({ channel, guild })); }, [guild, channel]); - if (!guild && guilds.length) + if (!guild) return ; - else if (!guild) return null; else if (guild.channels.length && !channelId) { const systemChannel = guild.channels[0]; return ; diff --git a/frontend/src/components/pages/loading-page.tsx b/frontend/src/components/pages/loading-page.tsx index 8b25458..930c522 100644 --- a/frontend/src/components/pages/loading-page.tsx +++ b/frontend/src/components/pages/loading-page.tsx @@ -1,6 +1,19 @@ +import { useEffect } from 'react'; import PageWrapper from './page-wrapper'; +import { ready } from '../../store/auth'; +import { useDispatch } from 'react-redux'; +import { fetchMyGuilds } from '../../store/guilds'; +import { fetchUsers } from '../../store/users'; const LoadingPage: React.FunctionComponent = () => { + const dispatch = useDispatch(); + + useEffect(() => { + dispatch(ready()); + dispatch(fetchMyGuilds()); + dispatch(fetchUsers()); + }, []); + const tips = [ 'This app took 2 weeks longer than expected to make.', 'Stealing Discord since 1966.', @@ -20,4 +33,4 @@ const LoadingPage: React.FunctionComponent = () => { ); } -export default LoadingPage; \ No newline at end of file +export default LoadingPage; diff --git a/frontend/src/components/pages/page-wrapper.tsx b/frontend/src/components/pages/page-wrapper.tsx index dc6c738..9586d6d 100644 --- a/frontend/src/components/pages/page-wrapper.tsx +++ b/frontend/src/components/pages/page-wrapper.tsx @@ -20,7 +20,6 @@ const PageWrapper: React.FunctionComponent = (props) => { const dropdown = useSelector((s: Store.AppStore) => s.ui.openDropdown); useEffect(() => { - dispatch(ready()); document.title = props.pageTitle ?? 'DClone'; }, []); diff --git a/frontend/src/components/routing/private-route.tsx b/frontend/src/components/routing/private-route.tsx index 76066a1..dbd0de7 100644 --- a/frontend/src/components/routing/private-route.tsx +++ b/frontend/src/components/routing/private-route.tsx @@ -1,26 +1,16 @@ -import { useEffect } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import { Redirect, Route, RouteProps } from 'react-router-dom'; -import { ready } from '../../store/auth'; -import { fetchMyGuilds } from '../../store/guilds'; -import { fetchUsers } from '../../store/users'; import LoadingPage from '../pages/loading-page'; // this route ensures that the user is logged in, else redirects them const PrivateRoute: React.FunctionComponent = (props) => { - const dispatch = useDispatch(); - const user = useSelector((s: Store.AppStore) => s.auth.user); - const attemptedLogin = useSelector((s: Store.AppStore) => s.auth.attemptedLogin); - - useEffect(() => { - dispatch(ready()); - dispatch(fetchMyGuilds()); - dispatch(fetchUsers()); - }, []); + const user = useSelector((s: Store.AppStore) => s.entities); + const { guilds, users } = useSelector((s: Store.AppStore) => s.entities); + const attemptedLogin = useSelector((s: Store.AppStore) => s.auth.attemptedLogin); if (attemptedLogin && !user) return ; - else if (!user) + else if (!users.fetched || !guilds.fetched) return ; return ( diff --git a/frontend/src/store/guilds.ts b/frontend/src/store/guilds.ts index 3622cdc..6b0599b 100644 --- a/frontend/src/store/guilds.ts +++ b/frontend/src/store/guilds.ts @@ -1,49 +1,52 @@ import { createSelector, createSlice } from '@reduxjs/toolkit'; import { actions as api } from './api'; -import { focusedInvite } from './ui'; const slice = createSlice({ name: 'guilds', - initialState: [] as Entity.Guild[], + initialState: { + fetched: false, + list: [] as Entity.Guild[], + }, reducers: { created: (guilds, { payload }) => { - guilds.push(payload.guild); + guilds.list.push(payload.guild); }, channelCreated: (guilds, { payload }) => { - const guild = guilds.find(g => g.id === payload.channel.guildId); + const guild = guilds.list.find(g => g.id === payload.channel.guildId); guild!.channels.push(payload.channel); }, channelDeleted: (guilds, { payload }) => { - const guild = guilds.find(g => g.id === payload.guildId); + const guild = guilds.list.find(g => g.id === payload.guildId); guild!.channels = guild!.channels.filter(c => c.id !== payload.channelId); }, inviteCreated: (guilds, { payload }) => { - const guild = guilds.find(g => g.id === payload.invite.guildId); + const guild = guilds.list.find(g => g.id === payload.invite.guildId); guild!.invites.push(payload.invite); }, memberAdded: (guilds, { payload }) => { - const guild = guilds.find(i => i.id === payload.guildId); + const guild = guilds.list.find(i => i.id === payload.guildId); guild!.members.push(payload.member); }, memberRemoved: (guilds, { payload }) => { - const guild = guilds.find(i => i.id === payload.guildId)!; + const guild = guilds.list.find(i => i.id === payload.guildId)!; guild.members = guild.members.filter(m => m.id !== payload.userId); }, memberUpdated: (guilds, { payload }) => { - const members = guilds.flatMap(g => g.members); + const members = guilds.list.flatMap(g => g.members); const member = members.find(m => m.id === payload.userId); Object.assign(member, payload.payload); }, fetched: (guilds, { payload }) => { - guilds.push(...(payload ?? [])); + guilds.list.push(...(payload ?? [])); + guilds.fetched = true; }, updated: (guilds, { payload }) => { - const guild = guilds.find(i => i.id === payload.guildId); + const guild = guilds.list.find(i => i.id === payload.guildId); Object.assign(guild, payload.payload); }, deleted: (guilds, { payload }) => { - const index = guilds.findIndex(u => u.id === payload.guildId); - guilds.splice(index, 1); + const index = guilds.list.findIndex(u => u.id === payload.guildId); + guilds.list.splice(index, 1); }, }, }); @@ -53,7 +56,7 @@ export default slice.reducer; export const fetchMyGuilds = () => (dispatch, getState: () => Store.AppStore) => { const guilds = getState().entities.guilds; - if (guilds.length) return; + if (guilds.list.length) return; dispatch(api.restCallBegan({ onSuccess: [actions.fetched.type], @@ -129,17 +132,17 @@ export const createInvite = (guildId: string) => (dispatch) => { export const getGuild = (id: string) => createSelector( - state => state.entities.guilds, + state => state.entities.guilds.list, guilds => guilds.find(g => g.id === id), ); export const getGuildByChannelId = (channelId: string) => createSelector( - state => state.entities.guilds, + state => state.entities.guilds.list, guilds => guilds.find(g => g.channels.some(c => c.id === channelId)), ); export const getChannel = (guildId: string, channelId: string) => createSelector( - state => state.entities.guilds, + state => state.entities.guilds.list, guilds => guilds .find(g => g.id === guildId)?.channels .find(c => c.id === channelId), diff --git a/frontend/src/store/users.ts b/frontend/src/store/users.ts index 4972935..438ebd4 100644 --- a/frontend/src/store/users.ts +++ b/frontend/src/store/users.ts @@ -3,21 +3,25 @@ import { actions as api } from './api'; const slice = createSlice({ name: 'users', - initialState: [] as Entity.User[], + initialState: { + fetched: false, + list: [] as Entity.User[], + }, reducers: { fetched: (users, { payload }) => { - // TODO: remove try catch - try { users.push(...payload) } - catch { users.push(payload) } + try { users.list.push(...payload) } // called when self user fetched (READY) + catch { // called when all users fetched (GET users) + users.list.push(payload); + users.fetched = true; + } }, updated: (users, { payload }) => { - const user = users.find(u => u.id === payload.userId); - // TODO: fix bad naming + const user = users.list.find(u => u.id === payload.userId); Object.assign(user, payload.payload); }, deleted: (users, { payload }) => { - const index = users.findIndex(u => u.id === payload.userId); - users.splice(index, 1); + const index = users.list.findIndex(u => u.id === payload.userId); + users.list.splice(index, 1); }, }, }); @@ -47,6 +51,6 @@ export const deleteSelf = () => (dispatch) => { export const getUser = (id: string) => createSelector( - state => state.entities.users, + state => state.entities.users.list, users => users.find(u => u.id === id), ); diff --git a/types/store.d.ts b/types/store.d.ts index d3870ae..aecb5a9 100644 --- a/types/store.d.ts +++ b/types/store.d.ts @@ -11,9 +11,15 @@ declare namespace Store { channels: { typing: { userId: string, channelId: string }[]; }; - guilds: Entity.Guild[]; + guilds: { + fetched: boolean; + list: Entity.Guild[]; + } messages: Entity.Message[]; - users: Entity.User[]; + users: { + fetched: boolean; + list: Entity.User[]; + } }; // metadata about store meta: {