cleanup of the frontend code

- replace undocumented `substr` with `substring`
- remove unused code
- inline a few variables
- simplify ifs when possible
- improve saveCollapsedComments documentation
- cleanup the unused imports
- remove unused variables and types
This commit is contained in:
Dmitry Verkhoturov
2023-01-09 22:16:35 +01:00
parent 596861a594
commit d6cce8df2c
22 changed files with 14 additions and 102 deletions
-2
View File
@@ -9,8 +9,6 @@ export const getConfig = (): Promise<Config> => apiFetcher.get('/config');
export const getPostComments = (sort: Sorting) => apiFetcher.get<Tree>('/find', { url, sort, format: 'tree' });
export const getComment = (id: Comment['id']): Promise<Comment> => apiFetcher.get(`/id/${id}`, { url });
export const getUserComments = (
userId: User['id'],
config: { limit: number; skip?: number } = { limit: 10, skip: 0 }
@@ -43,7 +43,3 @@ export function getCookie(name: string) {
return matches ? decodeURIComponent(matches[1]) : undefined;
}
export function deleteCookie(name: string) {
setCookie(name, '', { expires: -1 });
}
+1 -3
View File
@@ -69,9 +69,7 @@ const createFetcher = (baseUrl: string = ''): Methods => {
// TODO: it should be clarified when frontend gets this header and what could be in it to simplify this logic and cover by tests
const date = (res.headers.has('date') && res.headers.get('date')) || '';
const timestamp = isNaN(Date.parse(date)) ? 0 : Date.parse(date);
const timeDiff = (new Date().getTime() - timestamp) / 1000;
StaticStore.serverClientTimeDiff = timeDiff;
StaticStore.serverClientTimeDiff = (new Date().getTime() - timestamp) / 1000;
// backend could update jwt in any time. so, we should handle it
if (res.headers.has(JWT_HEADER)) {
@@ -72,12 +72,6 @@ export interface Comment {
*/
hidden?: boolean;
}
export interface CommentsResponse {
comments: Comment[];
count: number;
}
export interface Node {
comment: Comment;
replies?: Node[];
@@ -123,7 +123,7 @@ export function useErrorMessage(): [string | null, (e: unknown) => void] {
}
const errorReason =
err instanceof RequestError || (isObject(err) && typeof (err as Record<string, string>).error === 'string')
err instanceof RequestError || isObject(err)
? (err as Record<'error', string>).error
: err instanceof Error
? err.message
@@ -26,7 +26,6 @@ const emailRegexp = /[^@]+@[^.]+\..+/;
enum Step {
Email,
Token,
Final,
Close,
Subscribed,
Unsubscribed,
@@ -112,7 +112,7 @@ export class CommentForm extends Component<Props, State> {
onInput = (e: Event) => {
const { value } = e.target as HTMLInputElement;
const text = value.substr(0, StaticStore.config.max_comment_size);
const text = value.substring(0, StaticStore.config.max_comment_size);
updatePersistedComments(this.props.id, value);
@@ -56,7 +56,7 @@ describe('<CommentVote />', () => {
['downvote', -1, 'Vote down', 'Vote up', 'downVoteButtonActive'],
])(
'should go throught voting process and communicate with store when %s button is clicked',
async (_, increment, activeButtonText, secondButtonText, activeButtonClass) => {
async (_, increment, activeButtonText, secondButtonText) => {
const putCommentVoteSpy = jest
.spyOn(api, 'putCommentVote')
.mockImplementationOnce(({ vote }) => Promise.resolve({ id: '1', score: 10 + vote }));
@@ -21,7 +21,7 @@ type Props = {
disabled?: boolean;
};
export function CommentVotes({ id, votes, vote, disabled, controversy = 0 }: Props) {
export function CommentVotes({ id, votes, vote, disabled }: Props) {
const intl = useIntl();
const dispatch = useDispatch();
const [loadingState, setLoadingState] = useState<{ vote: number; votes: number } | null>(null);
@@ -62,7 +62,6 @@ export interface State {
}
export class Comment extends Component<CommentProps, State> {
votingPromise: Promise<unknown> = Promise.resolve();
/** comment text node. Used in comment text copying */
textNode = createRef<HTMLDivElement>();
@@ -175,16 +174,6 @@ export class Comment extends Component<CommentProps, State> {
}
};
onBlockUserClick = (evt: Event) => {
const target = evt.currentTarget;
if (target instanceof HTMLOptionElement) {
// we have to debounce the blockUser function calls otherwise it will be
// called 2 times (by change event and by blur event)
this.blockUser(target.value as BlockTTL);
}
};
blockUser = debounce((ttl: BlockTTL): void => {
const { user } = this.props.data;
const blockingDurations = getBlockingDurations(this.props.intl);
@@ -427,7 +416,7 @@ export class Comment extends Component<CommentProps, State> {
/>
</button>
)}
{!isAdmin && !!o.user.verified && props.view !== 'user' && (
{!isAdmin && o.user.verified && props.view !== 'user' && (
<VerificationIcon className={styles.verificationIcon} title={intl.formatMessage(messages.verifiedUser)} />
)}
{o.user.paid_sub && (
@@ -560,7 +549,7 @@ function getTextSnippet(html: string) {
tmp.innerHTML = html.replace('</p><p>', ' ');
const result = tmp.innerText || '';
const snippet = result.substr(0, LENGTH);
const snippet = result.substring(0, LENGTH);
return snippet.length === LENGTH && result.length !== LENGTH ? `${snippet}...` : snippet;
}
@@ -11,7 +11,6 @@ import { COMMENT_NODE_CLASSNAME_PREFIX, MAX_SHOWN_ROOT_COMMENTS, THEMES, IS_MOBI
import { maxShownComments, url } from 'common/settings';
import {
setUser,
fetchUser,
blockUser,
unblockUser,
@@ -20,7 +19,7 @@ import {
unhideUser,
signout,
} from 'store/user/actions';
import { fetchComments, addComment, updateComment, unsetCommentMode } from 'store/comments/actions';
import { fetchComments, addComment, updateComment } from 'store/comments/actions';
import { setCommentsReadOnlyState } from 'store/post-info/actions';
import { setTheme } from 'store/theme/actions';
@@ -73,7 +72,6 @@ const mapStateToProps = (state: StoreState) => ({
const boundActions = bindActions({
fetchComments,
setUser,
fetchUser,
fetchBlockedUsers,
setTheme,
@@ -85,7 +83,6 @@ const boundActions = bindActions({
addComment,
updateComment,
setCollapse,
unsetCommentMode,
signout,
});
@@ -91,8 +91,7 @@ class SettingsComponent extends Component<Props, State> {
};
__isUserHidden = (user: User): boolean => {
if (this.state.unhiddenUsers.indexOf(user.id) === -1) return true;
return false;
return !this.state.unhiddenUsers.includes(user.id);
};
render({ user, theme }: Props, { blockedUsers, unblockedUsers, unhiddenUsers }: State) {
@@ -2,7 +2,7 @@ import { h, JSX } from 'preact';
import { forwardRef } from 'preact/compat';
import { useEffect, useRef } from 'preact/hooks';
function autoResize(textarea: HTMLTextAreaElement, onResize?: () => void) {
function autoResize(textarea: HTMLTextAreaElement) {
textarea.style.height = '';
textarea.style.height = `${textarea.scrollHeight}px`;
}
+1 -3
View File
@@ -4,7 +4,5 @@ import { StoreState } from 'store';
import { Theme } from 'common/types';
export function useTheme() {
const theme = useSelector<StoreState, Theme>(({ theme }) => theme);
return theme;
return useSelector<StoreState, Theme>(({ theme }) => theme);
}
-15
View File
@@ -33,19 +33,4 @@ declare global {
| undefined;
};
}
namespace NodeJS {
interface Global {
Headers: typeof Headers;
localStorage: typeof Storage;
}
}
}
/**
* Variable responsive for dynamic setting public path for
* assets. Dynamic imports with relative url will be resolved over this path.
*
* https://webpack.js.org/guides/public-path/#on-the-fly
*/
declare let __webpack_public_path__: string;
@@ -1,8 +0,0 @@
export function bench<T>(fn: () => T, label = 'bench'): T {
const d = performance.now();
const r = fn();
const dd = performance.now();
// eslint-disable-next-line no-console
console.info(label, dd - d);
return r;
}
@@ -1,22 +0,0 @@
import { Node } from 'common/types';
/**
* Function to debug node tree.
*/
export function debugNode(n: Node): Node {
const d = (n: Node, level: number): void => {
// eslint-disable-next-line no-console
console.log(
`${' '.repeat(level)}${n.comment.text.trim()} | id: ${n.comment.id} | delete: ${n.comment.delete} | pin: ${
n.comment.pin
}`
);
if (n.replies) {
for (const node of n.replies) {
d(node, level + 1);
}
}
};
d(n, 0);
return n;
}
@@ -1,2 +0,0 @@
/** type that makes certain properties of type optional */
export type Derequire<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>> & Partial<Pick<T, K>>;
@@ -1,3 +1,3 @@
export function replaceSelection(text: string, selection: [number, number], replacement: string): string {
return text.substr(0, selection[0]) + replacement + text.substr(selection[1]);
return text.substring(0, selection[0]) + replacement + text.substring(selection[1]);
}
@@ -1,9 +0,0 @@
export function shallowCompare<T extends Record<string, unknown>>(a: T, b: T): boolean {
const entriesA = Object.entries(a);
const keysB = Object.keys(b);
if (entriesA.length !== keysB.length) return false;
for (const [key, value] of entriesA) {
if (value !== b[key]) return false;
}
return true;
}
@@ -52,7 +52,7 @@
var query = (function () {
if (window.location.search.length === 0) return {};
return window.location.search
.substr(1)
.substring(1)
.split('&')
.map(function (item) {
return item.split('=');
+1 -1
View File
@@ -75,7 +75,7 @@
window.location.search.length < 2
? {}
: window.location.search
.substr(1)
.substring(1)
.split('&')
.reduce(function (c, x) {
var splitted = x.split('=');