mirror of
https://github.com/plebbit/seedit.git
synced 2026-05-19 14:19:24 -04:00
refactor(utils): optimize checkCurrentView with switch, move all utils to their own file category in utils folder
This commit is contained in:
@@ -1,35 +1,40 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
import { Link, useLocation, useParams } from 'react-router-dom';
|
||||
import styles from './header.module.css';
|
||||
import useTheme from '../../hooks/use-theme';
|
||||
import AccountBar from './account-bar';
|
||||
import { useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import useCurrentView from '../../hooks/use-current-view';
|
||||
import { checkCurrentView } from '../../lib/utils/view-utils';
|
||||
|
||||
const sortTypes = ['/hot', '/new', '/active', '/controversialAll', '/topAll'];
|
||||
|
||||
const Header = () => {
|
||||
const [theme] = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const { sortType, subplebbitAddress, commentCid } = useParams();
|
||||
const [selectedSortType, setSelectedSortType] = useState(sortType || '/hot');
|
||||
const location = useLocation();
|
||||
const params = useParams();
|
||||
const [selectedSortType, setSelectedSortType] = useState(params.sortType || '/hot');
|
||||
const sortLabels = [t('header_hot'), t('header_new'), t('header_active'), t('header_controversial'), t('header_top')];
|
||||
const subplebbit = useSubplebbit({ subplebbitAddress });
|
||||
const subplebbit = useSubplebbit({ subplebbitAddress: params.subplebbitAddress });
|
||||
const { title, shortAddress } = subplebbit || {};
|
||||
const { isHomeView, isSubplebbitView, isPostView, isSubmitView, isSubplebbitSubmitView } = useCurrentView();
|
||||
const isHomeView = checkCurrentView('home', location.pathname, params)
|
||||
const isPostView = checkCurrentView('post', location.pathname, params)
|
||||
const isSubplebbitView = checkCurrentView('subplebbit', location.pathname, params)
|
||||
const isSubmitView = checkCurrentView('submit', location.pathname, params)
|
||||
const isSubplebbitSubmitView = checkCurrentView('subplebbit/submit', location.pathname, params)
|
||||
|
||||
const handleSelect = (choice: string) => {
|
||||
setSelectedSortType(choice);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (sortType) {
|
||||
setSelectedSortType('/' + sortType);
|
||||
if (params.sortType) {
|
||||
setSelectedSortType('/' + params.sortType);
|
||||
} else {
|
||||
setSelectedSortType('/hot');
|
||||
}
|
||||
}, [sortType]);
|
||||
}, [params.sortType]);
|
||||
|
||||
const sortItems = sortTypes.map((choice, index) => (
|
||||
<li key={choice}>
|
||||
@@ -41,7 +46,7 @@ const Header = () => {
|
||||
|
||||
const commentsButton = (
|
||||
<li>
|
||||
<Link to={`/p/${subplebbitAddress}/c/${commentCid}`} className={styles.selected}>
|
||||
<Link to={`/p/${params.subplebbitAddress}/c/${params.commentCid}`} className={styles.selected}>
|
||||
{t('header_comments')}
|
||||
</Link>
|
||||
</li>
|
||||
@@ -56,7 +61,7 @@ const Header = () => {
|
||||
|
||||
const subplebbitTitle = (
|
||||
<Link
|
||||
to={`/p/${subplebbitAddress}`}
|
||||
to={`/p/${params.subplebbitAddress}`}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import styles from './expand-button.module.css';
|
||||
import { CommentMediaInfo } from '../../../lib/utils';
|
||||
import { CommentMediaInfo } from '../../../lib/utils/media-utils';
|
||||
|
||||
interface ExpandButtonProps {
|
||||
commentMediaInfo?: CommentMediaInfo;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
import styles from './expando.module.css';
|
||||
import Embed from '../embed';
|
||||
import { CommentMediaInfo } from '../../../lib/utils';
|
||||
import { CommentMediaInfo } from '../../../lib/utils/media-utils';
|
||||
|
||||
interface ExpandoProps {
|
||||
commentMediaInfo?: CommentMediaInfo;
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import { useState } from 'react';
|
||||
import styles from './post.module.css';
|
||||
import { Link } from 'react-router-dom';
|
||||
import utils from '../../lib/utils';
|
||||
import { Link, useLocation, useParams } from 'react-router-dom';
|
||||
import { useAccount, Comment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { checkCurrentView } from '../../lib/utils/view-utils';
|
||||
import { getCommentMediaInfoMemoized, getHasThumbnail } from '../../lib/utils/media-utils';
|
||||
import { getHostname } from '../../lib/utils/url-utils';
|
||||
import { getFormattedTime } from '../../lib/utils/time-utils';
|
||||
import ExpandButton from './expand-button';
|
||||
import Expando from './expando';
|
||||
import Flair from './flair';
|
||||
import PostTools from './post-tools';
|
||||
import Thumbnail from './thumbnail';
|
||||
import useCurrentView from '../../hooks/use-current-view';
|
||||
|
||||
interface PostProps {
|
||||
index?: number;
|
||||
@@ -21,15 +23,18 @@ const Post = ({ post, index }: PostProps) => {
|
||||
const account = useAccount();
|
||||
const subplebbit = useSubplebbit({ subplebbitAddress });
|
||||
const { t } = useTranslation();
|
||||
const params = useParams();
|
||||
const location = useLocation();
|
||||
|
||||
const { isPendingView, isPostView } = useCurrentView();
|
||||
const isPostView = checkCurrentView('post', location.pathname, params);
|
||||
const isPendingView = checkCurrentView('pending', location.pathname, params);
|
||||
const isInPostView = isPostView || isPendingView;
|
||||
const [isExpanded, setIsExpanded] = useState(isInPostView);
|
||||
const toggleExpanded = () => setIsExpanded(!isExpanded);
|
||||
|
||||
const commentMediaInfo = utils.getCommentMediaInfoMemoized(post);
|
||||
const hasThumbnail = utils.hasThumbnail(commentMediaInfo, link);
|
||||
const linkUrl = utils.getHostname(link);
|
||||
const commentMediaInfo = getCommentMediaInfoMemoized(post);
|
||||
const hasThumbnail = getHasThumbnail(commentMediaInfo, link);
|
||||
const linkUrl = getHostname(link);
|
||||
|
||||
const postAuthor = isPendingView ? account?.author?.shortAddress : author?.shortAddress;
|
||||
const postScore = upvoteCount === 0 && downvoteCount === 0 ? '•' : upvoteCount - downvoteCount || '•';
|
||||
@@ -99,7 +104,7 @@ const Post = ({ post, index }: PostProps) => {
|
||||
/>
|
||||
)}
|
||||
<p className={styles.tagline}>
|
||||
{t('post_submitted')} {utils.getFormattedTime(timestamp)} {t('post_by')}{' '}
|
||||
{t('post_submitted')} {getFormattedTime(timestamp)} {t('post_by')}{' '}
|
||||
<Link className={styles.author} to={`u/${postAuthor}`} onClick={(e) => e.preventDefault()}>
|
||||
u/{postAuthor}
|
||||
</Link>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import styles from './thumbnail.module.css';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { CommentMediaInfo } from '../../../lib/utils';
|
||||
import { CommentMediaInfo } from '../../../lib/utils/media-utils';
|
||||
|
||||
interface ThumbnailProps {
|
||||
cid?: string;
|
||||
|
||||
@@ -4,7 +4,8 @@ import { Link } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import styles from './reply.module.css';
|
||||
import useReplies from '../../hooks/use-replies';
|
||||
import utils from '../../lib/utils';
|
||||
import { getCommentMediaInfoMemoized, getHasThumbnail } from '../../lib/utils/media-utils';
|
||||
import { getFormattedTime } from '../../lib/utils/time-utils';
|
||||
import Expando from '../post/expando/';
|
||||
import ExpandButton from '../post/expand-button/';
|
||||
import Thumbnail from '../post/thumbnail/';
|
||||
@@ -32,8 +33,8 @@ const Reply = ({ reply }: ReplyProps) => {
|
||||
const replies = useReplies(reply);
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const toggleExpanded = () => setExpanded(!expanded);
|
||||
const commentMediaInfo = utils.getCommentMediaInfoMemoized(reply);
|
||||
const hasThumbnail = utils.hasThumbnail(commentMediaInfo, link);
|
||||
const commentMediaInfo = getCommentMediaInfoMemoized(reply);
|
||||
const hasThumbnail = getHasThumbnail(commentMediaInfo, link);
|
||||
const { t } = useTranslation();
|
||||
let score = upvoteCount - downvoteCount;
|
||||
if ((upvoteCount === 0 && downvoteCount === 0) || (upvoteCount === 1 && downvoteCount === 0)) {
|
||||
@@ -61,7 +62,7 @@ const Reply = ({ reply }: ReplyProps) => {
|
||||
>
|
||||
{shortAddress}
|
||||
</Link>
|
||||
<span className={styles.score}>{scoreTranslation}</span> <span className={styles.time}>{utils.getFormattedTime(timestamp)}</span>
|
||||
<span className={styles.score}>{scoreTranslation}</span> <span className={styles.time}>{getFormattedTime(timestamp)}</span>
|
||||
{flair && (
|
||||
<>
|
||||
{' '}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import { useLocation, useParams } from 'react-router-dom';
|
||||
|
||||
type CurrentView = {
|
||||
isHomeView: boolean;
|
||||
isPendingView: boolean;
|
||||
isPostView: boolean;
|
||||
isSubmitView: boolean;
|
||||
isSubplebbitView: boolean;
|
||||
isSubplebbitSubmitView: boolean;
|
||||
};
|
||||
|
||||
type ParamsType = {
|
||||
accountCommentIndex?: string;
|
||||
commentCid?: string;
|
||||
subplebbitAddress?: string;
|
||||
};
|
||||
|
||||
const sortTypes = ['/hot', '/new', '/active', '/controversialAll', '/topAll'];
|
||||
|
||||
const useCurrentView = (): CurrentView => {
|
||||
const location = useLocation();
|
||||
const { accountCommentIndex, commentCid, subplebbitAddress } = useParams<ParamsType>();
|
||||
const pathname = location.pathname;
|
||||
|
||||
const isHomeView = pathname === `/` || sortTypes.includes(pathname);
|
||||
const isPendingView = pathname === `/profile/${accountCommentIndex}`;
|
||||
const isPostView = subplebbitAddress && commentCid ? pathname.startsWith(`/p/${subplebbitAddress}/c/${commentCid}`) : false;
|
||||
const isSubmitView = pathname === `/submit`;
|
||||
const isSubplebbitView = subplebbitAddress ? pathname.startsWith(`/p/${subplebbitAddress}`) : false;
|
||||
const isSubplebbitSubmitView = subplebbitAddress ? pathname === `/p/${subplebbitAddress}/submit` : false;
|
||||
|
||||
return { isHomeView, isSubplebbitView, isPendingView, isPostView, isSubmitView, isSubplebbitSubmitView };
|
||||
};
|
||||
|
||||
export default useCurrentView;
|
||||
163
src/lib/utils.ts
163
src/lib/utils.ts
@@ -1,163 +0,0 @@
|
||||
import i18next from 'i18next';
|
||||
import memoize from 'memoizee';
|
||||
import extName from 'ext-name';
|
||||
import { ChallengeVerification, Comment } from '@plebbit/plebbit-react-hooks';
|
||||
import { canEmbed } from '../components/post/embed';
|
||||
|
||||
export interface CommentMediaInfo {
|
||||
url: string;
|
||||
type: string;
|
||||
thumbnail?: string;
|
||||
patternThumbnailUrl?: string;
|
||||
}
|
||||
|
||||
export const alertChallengeVerificationFailed = (challengeVerification: ChallengeVerification, publication: any) => {
|
||||
if (challengeVerification?.challengeSuccess === false) {
|
||||
console.warn(challengeVerification, publication);
|
||||
alert(`p/${publication?.subplebbitAddress} challenge error: ${[...(challengeVerification?.challengeErrors || []), challengeVerification?.reason].join(' ')}`);
|
||||
} else {
|
||||
console.log(challengeVerification, publication);
|
||||
}
|
||||
};
|
||||
|
||||
const getCommentMediaInfo = (comment: Comment) => {
|
||||
if (!comment?.thumbnailUrl && !comment?.link) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (comment?.link) {
|
||||
let mime: string | undefined;
|
||||
try {
|
||||
mime = extName(new URL(comment?.link).pathname.toLowerCase().replace('/', ''))[0]?.mime;
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
const url = new URL(comment.link);
|
||||
const host = url.hostname;
|
||||
let patternThumbnailUrl;
|
||||
|
||||
if (['youtube.com', 'www.youtube.com', 'youtu.be'].includes(host)) {
|
||||
const videoId = host === 'youtu.be' ? url.pathname.slice(1) : url.searchParams.get('v');
|
||||
patternThumbnailUrl = `https://img.youtube.com/vi/${videoId}/sddefault.jpg`;
|
||||
} else if (host.includes('streamable.com')) {
|
||||
const videoId = url.pathname.split('/')[1];
|
||||
patternThumbnailUrl = `https://cdn-cf-east.streamable.com/image/${videoId}.jpg`;
|
||||
}
|
||||
|
||||
if (canEmbed(url)) {
|
||||
return {
|
||||
url: comment.link,
|
||||
type: 'iframe',
|
||||
thumbnail: comment.thumbnailUrl,
|
||||
patternThumbnailUrl,
|
||||
};
|
||||
}
|
||||
|
||||
if (mime?.startsWith('image')) {
|
||||
return { url: comment.link, type: 'image' };
|
||||
}
|
||||
if (mime?.startsWith('video')) {
|
||||
return { url: comment.link, type: 'video', thumbnail: comment.thumbnailUrl };
|
||||
}
|
||||
if (mime?.startsWith('audio')) {
|
||||
return { url: comment.link, type: 'audio' };
|
||||
}
|
||||
|
||||
if (comment?.thumbnailUrl && comment?.thumbnailUrl !== comment?.link) {
|
||||
return { url: comment.link, type: 'webpage', thumbnail: comment.thumbnailUrl };
|
||||
}
|
||||
|
||||
if (comment?.link) {
|
||||
return { url: comment.link, type: 'webpage' };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getCommentMediaInfoMemoized = memoize(getCommentMediaInfo, { max: 1000 });
|
||||
|
||||
const getFormattedTime = (unixTimestamp: number): string => {
|
||||
const currentTime = Date.now() / 1000;
|
||||
const timeDifference = currentTime - unixTimestamp;
|
||||
const t = i18next.t;
|
||||
|
||||
if (timeDifference < 60) {
|
||||
return t('time_1_minute_ago');
|
||||
}
|
||||
if (timeDifference < 3600) {
|
||||
return t('time_x_minutes_ago', { count: Math.floor(timeDifference / 60) });
|
||||
}
|
||||
if (timeDifference < 7200) {
|
||||
return t('time_1_hour_ago');
|
||||
}
|
||||
if (timeDifference < 86400) {
|
||||
return t('time_x_hours_ago', { count: Math.floor(timeDifference / 3600) });
|
||||
}
|
||||
if (timeDifference < 172800) {
|
||||
return t('time_1_day_ago');
|
||||
}
|
||||
if (timeDifference < 2592000) {
|
||||
return t('time_x_days_ago', { count: Math.floor(timeDifference / 86400) });
|
||||
}
|
||||
if (timeDifference < 5184000) {
|
||||
return t('time_1_month_ago');
|
||||
}
|
||||
if (timeDifference < 31104000) {
|
||||
return t('time_x_months_ago', { count: Math.floor(timeDifference / 2592000) });
|
||||
}
|
||||
if (timeDifference < 62208000) {
|
||||
return t('time_1_year_ago');
|
||||
}
|
||||
return t('time_x_years_ago', { count: Math.floor(timeDifference / 31104000) });
|
||||
};
|
||||
|
||||
const getHostname = (url: string) => {
|
||||
try {
|
||||
return new URL(url).hostname.replace(/^www\./, '');
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
const hasThumbnail = (commentMediaInfo: CommentMediaInfo | undefined, link: string | undefined): boolean => {
|
||||
const iframeThumbnail = commentMediaInfo?.patternThumbnailUrl || commentMediaInfo?.thumbnail;
|
||||
return link &&
|
||||
commentMediaInfo &&
|
||||
(commentMediaInfo.type === 'image' ||
|
||||
commentMediaInfo.type === 'video' ||
|
||||
(commentMediaInfo.type === 'webpage' && commentMediaInfo.thumbnail) ||
|
||||
(commentMediaInfo.type === 'iframe' && iframeThumbnail))
|
||||
? true
|
||||
: false;
|
||||
};
|
||||
|
||||
export const isValidENS = (address: string) => {
|
||||
return address.endsWith('.eth');
|
||||
};
|
||||
|
||||
export const isValidIPFS = (address: string) => {
|
||||
const IPFS_REGEX = /^12D3KooW[A-Za-z0-9]+$/;
|
||||
return IPFS_REGEX.test(address) && address.length === 52;
|
||||
};
|
||||
|
||||
export const isValidURL = (url: string) => {
|
||||
try {
|
||||
new URL(url);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const utils = {
|
||||
alertChallengeVerificationFailed,
|
||||
getCommentMediaInfoMemoized,
|
||||
getFormattedTime,
|
||||
getHostname,
|
||||
hasThumbnail,
|
||||
isValidENS,
|
||||
isValidIPFS,
|
||||
isValidURL,
|
||||
};
|
||||
|
||||
export default utils;
|
||||
10
src/lib/utils/challenge-utils.ts
Normal file
10
src/lib/utils/challenge-utils.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { ChallengeVerification } from '@plebbit/plebbit-react-hooks';
|
||||
|
||||
export const alertChallengeVerificationFailed = (challengeVerification: ChallengeVerification, publication: any) => {
|
||||
if (challengeVerification?.challengeSuccess === false) {
|
||||
console.warn(challengeVerification, publication);
|
||||
alert(`p/${publication?.subplebbitAddress} challenge error: ${[...(challengeVerification?.challengeErrors || []), challengeVerification?.reason].join(' ')}`);
|
||||
} else {
|
||||
console.log(challengeVerification, publication);
|
||||
}
|
||||
};
|
||||
79
src/lib/utils/media-utils.ts
Normal file
79
src/lib/utils/media-utils.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { Comment } from "@plebbit/plebbit-react-hooks";
|
||||
import extName from 'ext-name';
|
||||
import { canEmbed } from "../../components/post/embed";
|
||||
import memoize from 'memoizee';
|
||||
|
||||
export interface CommentMediaInfo {
|
||||
url: string;
|
||||
type: string;
|
||||
thumbnail?: string;
|
||||
patternThumbnailUrl?: string;
|
||||
}
|
||||
|
||||
export const getHasThumbnail = (commentMediaInfo: CommentMediaInfo | undefined, link: string | undefined): boolean => {
|
||||
const iframeThumbnail = commentMediaInfo?.patternThumbnailUrl || commentMediaInfo?.thumbnail;
|
||||
return link &&
|
||||
commentMediaInfo &&
|
||||
(commentMediaInfo.type === 'image' ||
|
||||
commentMediaInfo.type === 'video' ||
|
||||
(commentMediaInfo.type === 'webpage' && commentMediaInfo.thumbnail) ||
|
||||
(commentMediaInfo.type === 'iframe' && iframeThumbnail))
|
||||
? true
|
||||
: false;
|
||||
};
|
||||
|
||||
const getCommentMediaInfo = (comment: Comment) => {
|
||||
if (!comment?.thumbnailUrl && !comment?.link) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (comment?.link) {
|
||||
let mime: string | undefined;
|
||||
try {
|
||||
mime = extName(new URL(comment?.link).pathname.toLowerCase().replace('/', ''))[0]?.mime;
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
const url = new URL(comment.link);
|
||||
const host = url.hostname;
|
||||
let patternThumbnailUrl;
|
||||
|
||||
if (['youtube.com', 'www.youtube.com', 'youtu.be'].includes(host)) {
|
||||
const videoId = host === 'youtu.be' ? url.pathname.slice(1) : url.searchParams.get('v');
|
||||
patternThumbnailUrl = `https://img.youtube.com/vi/${videoId}/sddefault.jpg`;
|
||||
} else if (host.includes('streamable.com')) {
|
||||
const videoId = url.pathname.split('/')[1];
|
||||
patternThumbnailUrl = `https://cdn-cf-east.streamable.com/image/${videoId}.jpg`;
|
||||
}
|
||||
|
||||
if (canEmbed(url)) {
|
||||
return {
|
||||
url: comment.link,
|
||||
type: 'iframe',
|
||||
thumbnail: comment.thumbnailUrl,
|
||||
patternThumbnailUrl,
|
||||
};
|
||||
}
|
||||
|
||||
if (mime?.startsWith('image')) {
|
||||
return { url: comment.link, type: 'image' };
|
||||
}
|
||||
if (mime?.startsWith('video')) {
|
||||
return { url: comment.link, type: 'video', thumbnail: comment.thumbnailUrl };
|
||||
}
|
||||
if (mime?.startsWith('audio')) {
|
||||
return { url: comment.link, type: 'audio' };
|
||||
}
|
||||
|
||||
if (comment?.thumbnailUrl && comment?.thumbnailUrl !== comment?.link) {
|
||||
return { url: comment.link, type: 'webpage', thumbnail: comment.thumbnailUrl };
|
||||
}
|
||||
|
||||
if (comment?.link) {
|
||||
return { url: comment.link, type: 'webpage' };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const getCommentMediaInfoMemoized = memoize(getCommentMediaInfo, { max: 1000 });
|
||||
36
src/lib/utils/time-utils.ts
Normal file
36
src/lib/utils/time-utils.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import i18next from "i18next";
|
||||
|
||||
export const getFormattedTime = (unixTimestamp: number): string => {
|
||||
const currentTime = Date.now() / 1000;
|
||||
const timeDifference = currentTime - unixTimestamp;
|
||||
const t = i18next.t;
|
||||
|
||||
if (timeDifference < 60) {
|
||||
return t('time_1_minute_ago');
|
||||
}
|
||||
if (timeDifference < 3600) {
|
||||
return t('time_x_minutes_ago', { count: Math.floor(timeDifference / 60) });
|
||||
}
|
||||
if (timeDifference < 7200) {
|
||||
return t('time_1_hour_ago');
|
||||
}
|
||||
if (timeDifference < 86400) {
|
||||
return t('time_x_hours_ago', { count: Math.floor(timeDifference / 3600) });
|
||||
}
|
||||
if (timeDifference < 172800) {
|
||||
return t('time_1_day_ago');
|
||||
}
|
||||
if (timeDifference < 2592000) {
|
||||
return t('time_x_days_ago', { count: Math.floor(timeDifference / 86400) });
|
||||
}
|
||||
if (timeDifference < 5184000) {
|
||||
return t('time_1_month_ago');
|
||||
}
|
||||
if (timeDifference < 31104000) {
|
||||
return t('time_x_months_ago', { count: Math.floor(timeDifference / 2592000) });
|
||||
}
|
||||
if (timeDifference < 62208000) {
|
||||
return t('time_1_year_ago');
|
||||
}
|
||||
return t('time_x_years_ago', { count: Math.floor(timeDifference / 31104000) });
|
||||
};
|
||||
7
src/lib/utils/url-utils.ts
Normal file
7
src/lib/utils/url-utils.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export const getHostname = (url: string) => {
|
||||
try {
|
||||
return new URL(url).hostname.replace(/^www\./, '');
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
17
src/lib/utils/validation-utils.ts
Normal file
17
src/lib/utils/validation-utils.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
export const isValidENS = (address: string) => {
|
||||
return address.endsWith('.eth');
|
||||
};
|
||||
|
||||
export const isValidIPFS = (address: string) => {
|
||||
const IPFS_REGEX = /^12D3KooW[A-Za-z0-9]+$/;
|
||||
return IPFS_REGEX.test(address) && address.length === 52;
|
||||
};
|
||||
|
||||
export const isValidURL = (url: string) => {
|
||||
try {
|
||||
new URL(url);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
28
src/lib/utils/view-utils.ts
Normal file
28
src/lib/utils/view-utils.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
export type ParamsType = {
|
||||
accountCommentIndex?: string;
|
||||
commentCid?: string;
|
||||
subplebbitAddress?: string;
|
||||
};
|
||||
|
||||
export type ViewType = 'home' | 'pending' | 'post' | 'submit' | 'subplebbit' | 'subplebbit/submit';
|
||||
|
||||
const sortTypes = ['/hot', '/new', '/active', '/controversialAll', '/topAll'];
|
||||
|
||||
export const checkCurrentView = (view: ViewType, pathname: string, params: ParamsType): boolean => {
|
||||
switch (view) {
|
||||
case 'home':
|
||||
return pathname === '/' || sortTypes.includes(pathname);
|
||||
case 'pending':
|
||||
return pathname === `/profile/${params.accountCommentIndex}`;
|
||||
case 'post':
|
||||
return params.subplebbitAddress && params.commentCid ? pathname.startsWith(`/p/${params.subplebbitAddress}/c/${params.commentCid}`) : false;
|
||||
case 'submit':
|
||||
return pathname === '/submit';
|
||||
case 'subplebbit':
|
||||
return params.subplebbitAddress ? pathname.startsWith(`/p/${params.subplebbitAddress}`) : false;
|
||||
case 'subplebbit/submit':
|
||||
return params.subplebbitAddress ? pathname === `/p/${params.subplebbitAddress}/submit` : false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -1,12 +1,13 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { Link, useNavigate, useParams } from 'react-router-dom';
|
||||
import { Link, useLocation, useNavigate, useParams } from 'react-router-dom';
|
||||
import { usePublishComment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { create } from 'zustand';
|
||||
import { checkCurrentView } from '../../lib/utils/view-utils';
|
||||
import { alertChallengeVerificationFailed } from '../../lib/utils/challenge-utils';
|
||||
import { isValidENS, isValidIPFS, isValidURL } from '../../lib/utils/validation-utils';
|
||||
import styles from './submit.module.css';
|
||||
import useCurrentView from '../../hooks/use-current-view';
|
||||
import challengesStore from '../../hooks/use-challenges';
|
||||
import { alertChallengeVerificationFailed, isValidENS, isValidIPFS, isValidURL } from '../../lib/utils';
|
||||
|
||||
type SubmitStoreState = {
|
||||
subplebbitAddress: string | undefined;
|
||||
@@ -50,8 +51,9 @@ const useSubmitStore = create<SubmitStoreState>((set) => ({
|
||||
|
||||
const Submit = () => {
|
||||
const { t } = useTranslation();
|
||||
const { isSubplebbitSubmitView } = useCurrentView();
|
||||
const location = useLocation();
|
||||
const params = useParams();
|
||||
const isSubplebbitSubmitView = checkCurrentView('subplebbit/submit', location.pathname, params);
|
||||
const paramsSubplebbitAddress = params.subplebbitAddress;
|
||||
const subplebbit = useSubplebbit({ subplebbitAddress: paramsSubplebbitAddress });
|
||||
const navigate = useNavigate();
|
||||
|
||||
Reference in New Issue
Block a user