mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-19 19:21:33 +10:00
fix(client): 🐛 do not allow private resumes to be viewable or downloadable through the link
This commit is contained in:
@ -42,14 +42,10 @@ const Build: NextPage<Props> = ({ username, slug }) => {
|
||||
`resume/${username}/${slug}`,
|
||||
() => fetchResumeByIdentifier({ username, slug }),
|
||||
{
|
||||
cacheTime: 0,
|
||||
refetchOnMount: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnWindowFocus: false,
|
||||
onSuccess: (resume) => {
|
||||
dispatch(setResume(resume));
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@ -62,7 +58,7 @@ const Build: NextPage<Props> = ({ username, slug }) => {
|
||||
<div className={styles.container}>
|
||||
<Head>
|
||||
<title>
|
||||
{resume.name} | {t<string>('common.title')}
|
||||
{resume.name} | {t('common.title')}
|
||||
</title>
|
||||
</Head>
|
||||
|
||||
|
||||
@ -57,6 +57,16 @@ const Preview: NextPage<Props> = ({ username, slug, resume: initialData }) => {
|
||||
|
||||
useEffect(() => {
|
||||
if (initialData && !isEmpty(initialData)) {
|
||||
const errorObj = JSON.parse(JSON.stringify(initialData));
|
||||
const statusCode: number | null = get(errorObj, 'statusCode', null);
|
||||
|
||||
if (statusCode === 404) {
|
||||
toast.error('The resume you were looking for does not exist, or maybe it never did?');
|
||||
|
||||
router.push('/');
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(setResume(initialData));
|
||||
}
|
||||
}, [dispatch, initialData]);
|
||||
@ -73,10 +83,6 @@ const Preview: NextPage<Props> = ({ username, slug, resume: initialData }) => {
|
||||
|
||||
useQuery<Resume>(`resume/${username}/${slug}`, () => fetchResumeByIdentifier({ username, slug }), {
|
||||
initialData,
|
||||
retry: false,
|
||||
refetchOnMount: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnWindowFocus: false,
|
||||
onSuccess: (data) => {
|
||||
dispatch(setResume(data));
|
||||
},
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
import '@/styles/globals.scss';
|
||||
import '@fontsource/material-icons';
|
||||
import '@fontsource/ibm-plex-sans/300.css';
|
||||
import '@fontsource/ibm-plex-sans/400.css';
|
||||
import '@fontsource/ibm-plex-sans/500.css';
|
||||
import '@fontsource/ibm-plex-sans/600.css';
|
||||
import '@fontsource/ibm-plex-sans/700.css';
|
||||
|
||||
import env from '@beam-australia/react-env';
|
||||
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
|
||||
|
||||
@ -23,7 +23,7 @@ const Document: NextPage = () => (
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Organization",
|
||||
"url": "https://rxresu.me",
|
||||
"logo": "https://rxresu.me/images/logos/logo.svg"
|
||||
"logo": "https://rxresu.me/logo/dark.svg"
|
||||
}`,
|
||||
}}
|
||||
/>
|
||||
|
||||
@ -40,7 +40,7 @@ const Dashboard: NextPage = () => {
|
||||
<div className={styles.container}>
|
||||
<Head>
|
||||
<title>
|
||||
{t<string>('dashboard.title')} | {t<string>('common.title')}
|
||||
{t('dashboard.title')} | {t('common.title')}
|
||||
</title>
|
||||
</Head>
|
||||
|
||||
@ -56,15 +56,15 @@ const Dashboard: NextPage = () => {
|
||||
<ResumeCard
|
||||
icon={Add}
|
||||
modal="dashboard.create-resume"
|
||||
title={t<string>('dashboard.create-resume.title')}
|
||||
subtitle={t<string>('dashboard.create-resume.subtitle')}
|
||||
title={t('dashboard.create-resume.title')}
|
||||
subtitle={t('dashboard.create-resume.subtitle')}
|
||||
/>
|
||||
|
||||
<ResumeCard
|
||||
icon={ImportExport}
|
||||
modal="dashboard.import-external"
|
||||
title={t<string>('dashboard.import-external.title')}
|
||||
subtitle={t<string>('dashboard.import-external.subtitle')}
|
||||
title={t('dashboard.import-external.title')}
|
||||
subtitle={t('dashboard.import-external.subtitle')}
|
||||
/>
|
||||
|
||||
{data.map((resume) => (
|
||||
|
||||
68
client/pages/home.tsx
Normal file
68
client/pages/home.tsx
Normal file
@ -0,0 +1,68 @@
|
||||
import type { GetStaticProps, NextPage } from 'next';
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
||||
import Tilt from 'react-parallax-tilt';
|
||||
|
||||
import HeroBackground from '@/components/home/Background';
|
||||
import Footer from '@/components/home/Footer';
|
||||
import Header from '@/components/home/Header';
|
||||
import HeroPattern from '@/components/home/Pattern';
|
||||
import LogoSection from '@/components/home/sections/Logo';
|
||||
import StatsSection from '@/components/home/sections/Stats';
|
||||
import { defaultTiltProps } from '@/constants/tilt';
|
||||
|
||||
export const getStaticProps: GetStaticProps = async ({ locale = 'en' }) => ({
|
||||
props: {
|
||||
...(await serverSideTranslations(locale, ['common', 'modals', 'landing'])),
|
||||
},
|
||||
});
|
||||
|
||||
const Home: NextPage = () => (
|
||||
<div>
|
||||
<Header />
|
||||
|
||||
<main className="relative isolate mb-[450px] overflow-hidden bg-zinc-50 dark:bg-zinc-950">
|
||||
<section className="relative">
|
||||
<HeroPattern />
|
||||
<HeroBackground />
|
||||
|
||||
<div className="mx-auto max-w-7xl px-6 pb-24 pt-10 sm:pb-32 lg:flex lg:px-8 lg:py-52">
|
||||
<div className="mx-auto max-w-2xl shrink-0 lg:mx-0 lg:max-w-xl lg:pt-12">
|
||||
<div className="mt-10 space-y-2">
|
||||
<h6 className="text-base font-bold tracking-wide">Finally,</h6>
|
||||
<h1 className="text-4xl font-bold !leading-[1.15] tracking-tight sm:text-6xl">
|
||||
A free and open-source resume builder
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<p className="prose prose-base prose-zinc mt-6 text-lg leading-8 dark:prose-invert">
|
||||
Reactive Resume is a free and open-source resume builder that simplifies the tasks of creating, updating,
|
||||
and sharing your resume.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mx-auto mt-16 flex max-w-2xl sm:mt-24 lg:ml-10 lg:mr-0 lg:mt-0 lg:max-w-none lg:flex-none xl:ml-32">
|
||||
<div className="max-w-3xl flex-none sm:max-w-5xl lg:max-w-none">
|
||||
<Tilt {...defaultTiltProps}>
|
||||
<img
|
||||
width={2432}
|
||||
height={1442}
|
||||
src="/images/screenshots/builder.png"
|
||||
alt="Reactive Resume Screenshot - Builder Screen"
|
||||
className="w-[76rem] rounded-lg bg-zinc-50/5 shadow-2xl ring-1 ring-zinc-950/10 dark:bg-zinc-950/5 dark:ring-zinc-50/10"
|
||||
/>
|
||||
</Tilt>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<LogoSection />
|
||||
|
||||
<StatsSection />
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Home;
|
||||
@ -7,7 +7,7 @@ import Link from 'next/link';
|
||||
import { Trans, useTranslation } from 'next-i18next';
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
||||
|
||||
import Testimony from '@/components/landing/Testimony';
|
||||
import Testimony from '@/components/home/Testimony';
|
||||
import Footer from '@/components/shared/Footer';
|
||||
import LanguageSwitcher from '@/components/shared/LanguageSwitcher';
|
||||
import Logo from '@/components/shared/Logo';
|
||||
@ -49,28 +49,28 @@ const Home: NextPage = () => {
|
||||
</div>
|
||||
|
||||
<div className={styles.main}>
|
||||
<h1>{t<string>('common.title')}</h1>
|
||||
<h1>{t('common.title')}</h1>
|
||||
|
||||
<h2>{t<string>('common.subtitle')}</h2>
|
||||
<h2>{t('common.subtitle')}</h2>
|
||||
|
||||
<NoSsr>
|
||||
<div className={styles.buttonWrapper}>
|
||||
{isLoggedIn ? (
|
||||
<>
|
||||
<Link href="/dashboard" passHref>
|
||||
<Button>{t<string>('landing.actions.app')}</Button>
|
||||
<Button>{t('landing.actions.app')}</Button>
|
||||
</Link>
|
||||
|
||||
<Button variant="outlined" onClick={handleLogout}>
|
||||
{t<string>('landing.actions.logout')}
|
||||
{t('landing.actions.logout')}
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Button onClick={handleLogin}>{t<string>('landing.actions.login')}</Button>
|
||||
<Button onClick={handleLogin}>{t('landing.actions.login')}</Button>
|
||||
|
||||
<Button variant="outlined" onClick={handleRegister} disabled={FLAG_DISABLE_SIGNUPS}>
|
||||
{t<string>('landing.actions.register')}
|
||||
{t('landing.actions.register')}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
@ -80,21 +80,21 @@ const Home: NextPage = () => {
|
||||
</div>
|
||||
|
||||
<section className={styles.section}>
|
||||
<h6>{t<string>('landing.summary.heading')}</h6>
|
||||
<h6>{t('landing.summary.heading')}</h6>
|
||||
|
||||
<p>{t<string>('landing.summary.body')}</p>
|
||||
<p>{t('landing.summary.body')}</p>
|
||||
</section>
|
||||
|
||||
<section className={styles.section}>
|
||||
<h6>{t<string>('landing.features.heading')}</h6>
|
||||
<h6>{t('landing.features.heading')}</h6>
|
||||
|
||||
<ul className="list-inside list-disc leading-loose">
|
||||
<li>{t<string>('landing.features.list.free')}</li>
|
||||
<li>{t<string>('landing.features.list.ads')}</li>
|
||||
<li>{t<string>('landing.features.list.tracking')}</li>
|
||||
<li>{t<string>('landing.features.list.languages')}</li>
|
||||
<li>{t<string>('landing.features.list.import')}</li>
|
||||
<li>{t<string>('landing.features.list.export')}</li>
|
||||
<li>{t('landing.features.list.free')}</li>
|
||||
<li>{t('landing.features.list.ads')}</li>
|
||||
<li>{t('landing.features.list.tracking')}</li>
|
||||
<li>{t('landing.features.list.languages')}</li>
|
||||
<li>{t('landing.features.list.import')}</li>
|
||||
<li>{t('landing.features.list.export')}</li>
|
||||
<li>
|
||||
<Trans t={t} i18nKey="landing.features.list.more">
|
||||
And a lot of exciting features,
|
||||
@ -107,7 +107,7 @@ const Home: NextPage = () => {
|
||||
</section>
|
||||
|
||||
<section className={styles.section}>
|
||||
<h6>{t<string>('landing.screenshots.heading')}</h6>
|
||||
<h6>{t('landing.screenshots.heading')}</h6>
|
||||
|
||||
<div className={styles.screenshots}>
|
||||
{screenshots.map(({ src, alt }) => (
|
||||
@ -125,7 +125,7 @@ const Home: NextPage = () => {
|
||||
</section>
|
||||
|
||||
<section className={styles.section}>
|
||||
<h6>{t<string>('landing.testimonials.heading')}</h6>
|
||||
<h6>{t('landing.testimonials.heading')}</h6>
|
||||
|
||||
<p className="my-3">
|
||||
<Trans t={t} i18nKey="landing.testimonials.body">
|
||||
@ -150,42 +150,42 @@ const Home: NextPage = () => {
|
||||
</section>
|
||||
|
||||
<section className={styles.section}>
|
||||
<h6>{t<string>('landing.links.heading')}</h6>
|
||||
<h6>{t('landing.links.heading')}</h6>
|
||||
|
||||
<div>
|
||||
<Link href="/meta/privacy" passHref>
|
||||
<Button variant="text" startIcon={<LinkIcon />}>
|
||||
{t<string>('landing.links.links.privacy')}
|
||||
{t('landing.links.links.privacy')}
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<Link href="/meta/service" passHref>
|
||||
<Button variant="text" startIcon={<LinkIcon />}>
|
||||
{t<string>('landing.links.links.service')}
|
||||
{t('landing.links.links.service')}
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<a href={GITHUB_URL} target="_blank" rel="noreferrer">
|
||||
<Button variant="text" startIcon={<LinkIcon />}>
|
||||
{t<string>('landing.links.links.github')}
|
||||
{t('landing.links.links.github')}
|
||||
</Button>
|
||||
</a>
|
||||
|
||||
<a href={DOCS_URL} target="_blank" rel="noreferrer">
|
||||
<Button variant="text" startIcon={<LinkIcon />}>
|
||||
{t<string>('landing.links.links.docs')}
|
||||
{t('landing.links.links.docs')}
|
||||
</Button>
|
||||
</a>
|
||||
|
||||
<a href={REDDIT_URL} target="_blank" rel="noreferrer">
|
||||
<Button variant="text" startIcon={<LinkIcon />}>
|
||||
{t<string>('landing.links.links.reddit')}
|
||||
{t('landing.links.links.reddit')}
|
||||
</Button>
|
||||
</a>
|
||||
|
||||
<a href={DONATION_URL} target="_blank" rel="noreferrer">
|
||||
<Button variant="text" startIcon={<LinkIcon />}>
|
||||
{t<string>('landing.links.links.donate')}
|
||||
{t('landing.links.links.donate')}
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@ -41,9 +41,6 @@ const Preview: NextPage<Props> = ({ shortId }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const { data: resume } = useQuery<Resume>(`resume/${shortId}`, () => fetchResumeByShortId({ shortId }), {
|
||||
refetchOnMount: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnWindowFocus: false,
|
||||
onSuccess: (data) => {
|
||||
dispatch(setResume(data));
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user