Browse Source

Linter - manual fixes

Leszek Wiesner 4 years ago
parent
commit
177a0d4b6f

+ 6 - 8
pioneer/packages/joy-forum/src/CategoryList.tsx

@@ -206,13 +206,8 @@ type CategoryThreadsProps = ApiProps & InnerCategoryThreadsProps & {
 
 function InnerCategoryThreads (props: CategoryThreadsProps) {
   const { api, category, nextThreadId } = props;
-  const [currentPage, setCurrentPage] = usePagination();
-
-  if (!category.hasUnmoderatedThreads) {
-    return <em>No threads in this category</em>;
-  }
-
   const threadCount = category.num_threads_created.toNumber();
+  const [currentPage, setCurrentPage] = usePagination();
   const [loaded, setLoaded] = useState(false);
   const [threads, setThreads] = useState(new Array<Thread>());
 
@@ -253,9 +248,12 @@ function InnerCategoryThreads (props: CategoryThreadsProps) {
       setLoaded(true);
     };
 
-    loadThreads();
+    void loadThreads();
   }, [bnToStr(category.id), bnToStr(nextThreadId)]);
 
+  if (!category.hasUnmoderatedThreads) {
+    return <em>No threads in this category</em>;
+  }
   // console.log({ nextThreadId: bnToStr(nextThreadId), loaded, threads });
 
   if (!loaded) {
@@ -362,7 +360,7 @@ function InnerCategoryList (props: CategoryListProps) {
       setLoaded(true);
     };
 
-    loadCategories();
+    void loadCategories();
   }, [bnToStr(parentId), bnToStr(nextCategoryId)]);
 
   // console.log({ nextCategoryId: bnToStr(nextCategoryId), loaded, categories });

+ 7 - 7
pioneer/packages/joy-forum/src/Context.tsx

@@ -30,17 +30,17 @@ const initialState: ForumState = {
   sudo: undefined,
 
   nextCategoryId: 1,
-  categoryById: new Map(),
+  categoryById: new Map<CategoryId, Category>(),
   rootCategoryIds: [],
-  categoryIdsByParentId: new Map(),
+  categoryIdsByParentId: new Map<CategoryId, CategoryId[]>(),
 
   nextThreadId: 1,
-  threadById: new Map(),
-  threadIdsByCategoryId: new Map(),
+  threadById: new Map<ThreadId, Thread>(),
+  threadIdsByCategoryId: new Map<CategoryId, ThreadId[]>(),
 
   nextReplyId: 1,
-  replyById: new Map(),
-  replyIdsByThreadId: new Map()
+  replyById: new Map<ReplyId, Reply>(),
+  replyIdsByThreadId: new Map<ThreadId, ReplyId[]>()
 };
 
 type SetForumSudo = {
@@ -335,7 +335,7 @@ const contextStub: ForumContextProps = {
 
 export const ForumContext = createContext<ForumContextProps>(contextStub);
 
-export function ForumProvider (props: React.PropsWithChildren<{}>) {
+export function ForumProvider (props: React.PropsWithChildren<Record<any, unknown>>) {
   const [state, dispatch] = useReducer(reducer, initialState);
 
   return (

+ 1 - 1
pioneer/packages/joy-forum/src/EditReply.tsx

@@ -164,7 +164,7 @@ const InnerForm = (props: FormProps) => {
 
   const sectionTitle = isNew
     ? 'New reply'
-    : `Edit my reply #${struct?.nr_in_thread}`;
+    : `Edit my reply #${struct?.nr_in_thread.toString() || ''}`;
 
   return (
     <Section className='EditEntityBox' title={sectionTitle}>

+ 2 - 2
pioneer/packages/joy-forum/src/ForumRoot.tsx

@@ -98,7 +98,7 @@ const InnerRecentActivity: React.FC<RecentActivityProps> = ({ nextPostId, api })
       setLoaded(true);
     };
 
-    loadPosts();
+    void loadPosts();
   }, [bnToStr(nextPostId)]);
 
   useEffect(() => {
@@ -121,7 +121,7 @@ const InnerRecentActivity: React.FC<RecentActivityProps> = ({ nextPostId, api })
       setThreadsLookup(newLookup);
     };
 
-    loadThreads();
+    void loadThreads();
   }, [recentPosts]);
 
   const renderSectionContent = () => {

+ 8 - 5
pioneer/packages/joy-forum/src/ForumSudo.tsx

@@ -19,6 +19,7 @@ import AddressMini from '@polkadot/react-components/AddressMini';
 import { withForumCalls } from './calls';
 import { TxFailedCallback, TxCallback } from '@polkadot/react-components/Status/types';
 import { useApi } from '@polkadot/react-hooks';
+import { InputAddressProps } from '@polkadot/react-components/InputAddress/types';
 
 const buildSchema = () => Yup.object().shape({});
 
@@ -82,10 +83,12 @@ const InnerForm = (props: FormProps) => {
     return [api.createType('Option<AccountId>', sudo)];
   };
 
-  type SudoInputAddressProps = FieldProps<FormValues>; /* & InputAddressProps */
+  type SudoInputAddressProps = FieldProps<FormValues>;
 
   const SudoInputAddress = ({ field, form, ...props }: SudoInputAddressProps) => {
-    const { name, value } = field;
+    const { name } = field;
+    // Assert to avoid linter error
+    const value = field.value as InputAddressProps['value'];
 
     const onChange = (address: string | null) => {
       address !== value && form.setFieldValue(name, address);
@@ -220,7 +223,7 @@ function innerWithOnlyForumSudo<P extends LoadStructProps> (Component: React.Com
   };
 }
 
-export function withOnlyForumSudo<P extends {}> (Component: React.ComponentType<P>) {
+export function withOnlyForumSudo<P extends Record<string, unknown>> (Component: React.ComponentType<P>) {
   return withMulti(
     Component,
     withLoadForumSudo,
@@ -254,10 +257,10 @@ export function useForumSudo () {
   return useContext(ForumSudoContext);
 }
 
-export const IfIAmForumSudo = (props: React.PropsWithChildren<any>) => {
+export const IfIAmForumSudo = (props: React.PropsWithChildren<Record<any, unknown>>) => {
   const { forumSudo } = useForumSudo();
   const { state: { address: myAddress } } = useMyAccount();
   const iAmForumSudo: boolean = forumSudo !== undefined && forumSudo.eq(myAddress);
 
-  return iAmForumSudo ? props.children : null;
+  return iAmForumSudo ? <>{props.children}</> : null;
 };

+ 1 - 1
pioneer/packages/joy-forum/src/ViewReply.tsx

@@ -135,7 +135,7 @@ export const ViewReply = React.forwardRef((props: ViewReplyProps, ref: React.Ref
           <MemberPreview accountId={reply.author_id} showCouncilBadge showId={false}/>
         </ReplyHeaderAuthorRow>
         <ReplyHeaderDetailsRow>
-          <TimeAgoDate date={reply.created_at.momentDate} id={reply.id} />
+          <TimeAgoDate date={reply.created_at.momentDate} id={reply.id.toString()} />
           <Link to={{ pathname, search: replyLinkSearch.toString() }}>
             #{reply.nr_in_thread.toNumber()}
           </Link>

+ 34 - 37
pioneer/packages/joy-forum/src/ViewThread.tsx

@@ -143,43 +143,16 @@ function InnerViewThread (props: ViewThreadProps) {
 
   const editedPostId = rawEditedPostId && api.createType('PostId', rawEditedPostId);
 
-  if (!thread) {
-    return <em>Loading thread details...</em>;
-  }
-
-  const renderThreadNotFound = () => (
-    preview ? null : <em>Thread not found</em>
-  );
-
-  if (thread.isEmpty) {
-    return renderThreadNotFound();
-  }
-
   const { id } = thread;
   const totalPostsInThread = thread.num_posts_ever_created.toNumber();
 
-  const changePageAndClearSelectedPost = (page?: number | string) => {
-    setSelectedPostIdx(null);
-    setCurrentPage(page, [ReplyIdxQueryParam]);
-  };
-
-  if (!category) {
-    return <em>{'Thread\'s category was not found.'}</em>;
-  } else if (category.deleted) {
-    return renderThreadNotFound();
-  }
-
-  if (preview) {
-    return <ThreadPreview thread={thread} repliesCount={totalPostsInThread - 1} />;
-  }
-
   const [loaded, setLoaded] = useState(false);
   const [posts, setPosts] = useState(new Array<Post>());
 
   // fetch posts
   useEffect(() => {
     const loadPosts = async () => {
-      if (!nextPostId || totalPostsInThread === 0) return;
+      if (!nextPostId || totalPostsInThread === 0 || thread.isEmpty) return;
 
       const newId = (id: number | BN) => api.createType('PostId', id);
       const apiCalls: Promise<Post>[] = [];
@@ -214,7 +187,7 @@ function InnerViewThread (props: ViewThreadProps) {
       setLoaded(true);
     };
 
-    loadPosts();
+    void loadPosts();
   }, [bnToStr(thread.id), bnToStr(nextPostId)]);
 
   // handle selected post
@@ -259,6 +232,29 @@ function InnerViewThread (props: ViewThreadProps) {
     setDisplayedPosts(postsToDisplay);
   }, [loaded, posts, currentPage]);
 
+  const renderThreadNotFound = () => (
+    preview ? null : <em>Thread not found</em>
+  );
+
+  if (thread.isEmpty) {
+    return renderThreadNotFound();
+  }
+
+  if (!category) {
+    return <em>{'Thread\'s category was not found.'}</em>;
+  } else if (category.deleted) {
+    return renderThreadNotFound();
+  }
+
+  if (preview) {
+    return <ThreadPreview thread={thread} repliesCount={totalPostsInThread - 1} />;
+  }
+
+  const changePageAndClearSelectedPost = (page?: number | string) => {
+    setSelectedPostIdx(null);
+    setCurrentPage(page, [ReplyIdxQueryParam]);
+  };
+
   const scrollToReplyForm = () => {
     if (!replyFormRef.current) return;
     replyFormRef.current.scrollIntoView();
@@ -432,21 +428,18 @@ type ViewThreadByIdProps = RouteComponentProps<{ id: string }>;
 export function ViewThreadById (props: ViewThreadByIdProps) {
   const { api } = useApi();
   const { match: { params: { id } } } = props;
+  const [loaded, setLoaded] = useState(false);
+  const [thread, setThread] = useState(api.createType('Thread', {}));
+  const [category, setCategory] = useState(api.createType('Category', {}));
 
-  let threadId: ThreadId;
+  let threadId: ThreadId | undefined;
 
   try {
     threadId = api.createType('ThreadId', id);
   } catch (err) {
     console.log('Failed to parse thread id form URL');
-
-    return <em>Invalid thread ID: {id}</em>;
   }
 
-  const [loaded, setLoaded] = useState(false);
-  const [thread, setThread] = useState(api.createType('Thread', {}));
-  const [category, setCategory] = useState(api.createType('Category', {}));
-
   useEffect(() => {
     const loadThreadAndCategory = async () => {
       if (!threadId) return;
@@ -459,9 +452,13 @@ export function ViewThreadById (props: ViewThreadByIdProps) {
       setLoaded(true);
     };
 
-    loadThreadAndCategory();
+    void loadThreadAndCategory();
   }, [id]);
 
+  if (threadId === undefined) {
+    return <em>Invalid thread ID: {id}</em>;
+  }
+
   // console.log({ threadId: id, page });
 
   if (!loaded) {

+ 5 - 4
pioneer/packages/joy-forum/src/calls.tsx

@@ -16,13 +16,14 @@ const storage: StorageType = 'substrate';
 
 type EntityMapName = 'categoryById' | 'threadById' | 'replyById';
 
-const getReactValue = (state: ForumState, endpoint: string, paramValue: any): any => {
-  const getEntityById = (mapName: EntityMapName, type: keyof InterfaceTypes): any => {
+const getReactValue = (state: ForumState, endpoint: string, paramValue: any) => {
+  function getEntityById<T extends keyof InterfaceTypes>
+  (mapName: EntityMapName, type: T): InterfaceTypes[T] {
     const id = (paramValue as u64).toNumber();
     const entity = state[mapName].get(id);
 
     return createMock(type, entity);
-  };
+  }
 
   switch (endpoint) {
     case 'forumSudo': return createMock('Option<AccountId>', state.sudo);
@@ -37,7 +38,7 @@ function withReactCall<P extends ApiProps> (endpoint: string, { paramName, propN
   return (Inner: React.ComponentType<ApiProps>): React.ComponentType<SubtractProps<P, ApiProps>> => {
     const SetProp = (props: P) => {
       const { state } = useForum();
-      const paramValue = paramName ? (props as any)[paramName] : undefined;
+      const paramValue = paramName ? (props as Record<string, unknown>)[paramName] : undefined;
       const propValue = getReactValue(state, endpoint, paramValue);
       const _propName = propName || endpoint;
       const _props = {

+ 1 - 1
pioneer/packages/joy-forum/src/utils.tsx

@@ -127,7 +127,7 @@ export const CategoryCrumbs = ({ categoryId, threadId, root }: CategoryCrumbsPro
 
 type TimeAgoDateProps = {
   date: moment.Moment;
-  id: any;
+  id: string | number;
 };
 
 export const TimeAgoDate: React.FC<TimeAgoDateProps> = ({ date, id }) => (

+ 6 - 2
pioneer/packages/joy-utils/src/react/hocs/guards.tsx

@@ -68,14 +68,14 @@ type OnlySudoProps = {
 };
 
 function OnlySudo<P extends OnlySudoProps> (Component: React.ComponentType<P>) {
-  return function (props: P) {
+  const ResultComponent: React.FunctionComponent<P> = (props: P) => {
     const { sudo } = props;
+    const { state: { address: myAddress } } = useMyAccount();
 
     if (!sudo) {
       return <em>Loading sudo key...</em>;
     }
 
-    const { state: { address: myAddress } } = useMyAccount();
     const iAmSudo = myAddress === sudo.toString();
 
     if (iAmSudo) {
@@ -88,6 +88,10 @@ function OnlySudo<P extends OnlySudoProps> (Component: React.ComponentType<P>) {
       );
     }
   };
+
+  ResultComponent.displayName = `OnlySudo(${componentName(Component)})`;
+
+  return ResultComponent;
 }
 
 // TODO: We could probably use withAccountRequired, which wouldn't pass any addiotional props, just like withMembershipRequired.