diff --git a/next.config.js b/next.config.js index 658404a..d98bf89 100644 --- a/next.config.js +++ b/next.config.js @@ -1,4 +1,15 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {}; + +const nextConfig = { + async redirects() { + return [ + { + source: '/:shortCode', + destination: '/redirect/:shortCode', + permanent: false, + }, + ]; + }, +}; module.exports = nextConfig; diff --git a/public/assets/icons/redirect.tsx b/public/assets/icons/redirect.tsx new file mode 100644 index 0000000..5f1c95c --- /dev/null +++ b/public/assets/icons/redirect.tsx @@ -0,0 +1,7 @@ +const RedirectIcon = () => ( + + + +); + +export default RedirectIcon; diff --git a/src/constants/url.ts b/src/constants/url.ts index 60eb96d..e4e285a 100644 --- a/src/constants/url.ts +++ b/src/constants/url.ts @@ -2,3 +2,5 @@ export const TINY_API_URL = 'https://staging-tinysite-api.realdevsquad.com/v1'; export const TINY_API_GOOGLE_LOGIN = `${TINY_API_URL}/auth/google/login`; export const TINY_API_LOGOUT = `${TINY_API_URL}/auth/logout`; export const BASE_SHORT_URL = 'https://staging-tinysite.realdevsquad.com'; +export const TINY_API_URL_DETAIL = `${TINY_API_URL}/urls`; +export const TINY_API_REDIRECT = `${TINY_API_URL}/tinyurl`; diff --git a/src/pages/redirect/[redirect].tsx b/src/pages/redirect/[redirect].tsx new file mode 100644 index 0000000..32b2dd5 --- /dev/null +++ b/src/pages/redirect/[redirect].tsx @@ -0,0 +1,101 @@ +import fetchOriginalUrl from '@/utils/fetchOriginalUrl '; +import RedirectIcon from '../../../public/assets/icons/redirect'; +import { useState, useEffect } from 'react'; +import { useRouter } from 'next/router'; +import Head from 'next/head'; + +const Redirect = () => { + const router = useRouter(); + const { redirect: shortUrlCode } = router.query as { redirect: string }; + + const [originalUrl, setOriginalUrl] = useState(''); + const [timer, setTimer] = useState(5); + const [isPremiumUser, setIsPremiumUser] = useState(false); + const [showTooltip, setShowTooltip] = useState(false); + + useEffect(() => { + setIsPremiumUser(false); + }, []); + + useEffect(() => { + if (shortUrlCode) { + fetchOriginalUrl(shortUrlCode) + .then((url) => { + if (url) { + setOriginalUrl(url); + } else { + console.log('Short URL code not found'); + router.push('/'); + } + }) + .catch((error) => { + console.error('Error fetching original URL:', error); + }); + } + }, [shortUrlCode]); + + useEffect(() => { + if (timer > 0) { + const countdown = setTimeout(() => setTimer(timer - 1), 1000); + return () => clearTimeout(countdown); + } else if (timer === 0) { + router.push(originalUrl); + } + }, [timer, originalUrl]); + + const handleGoButtonClick = () => { + if (isPremiumUser) { + router.push(originalUrl); + } else { + setShowTooltip(true); + } + }; + + return ( + <> + + Redirecting... + + +
+

You are being redirected to:

+

{originalUrl}

+ {timer < 1 ? ( +
+ +

Redirecting...

+
+ ) : ( + <> +
+ {timer} +
+ + + )} + + {showTooltip && !isPremiumUser && ( +
+ Wait for {timer} seconds or become a premium user to skip the wait time. +
+ )} + +
+

This short URL generated by 

+ + Real Dev Squad URL Shortener + +
+
+ + ); +}; + +export default Redirect; diff --git a/src/types/url.types.ts b/src/types/url.types.ts new file mode 100644 index 0000000..0c1ddb6 --- /dev/null +++ b/src/types/url.types.ts @@ -0,0 +1,15 @@ +export interface UrlType { + Id: number; + OriginalUrl: string; + ShortUrl: string; + Comment: string; + UserId: number; + ExpiredAt: string; + CreatedAt: string; + CreatedBy: string; +} + +export interface UrlResponseTypes { + message: string; + url: UrlType; +} diff --git a/src/utils/fetchOriginalUrl .ts b/src/utils/fetchOriginalUrl .ts new file mode 100644 index 0000000..0c03429 --- /dev/null +++ b/src/utils/fetchOriginalUrl .ts @@ -0,0 +1,20 @@ +import { TINY_API_URL_DETAIL } from '@/constants/url'; +import { UrlResponseTypes } from '@/types/url.types'; + +async function fetchOriginalUrl(shortUrlCode: string): Promise { + try { + const response = await fetch(`${TINY_API_URL_DETAIL}/${shortUrlCode}`); + + if (response.ok) { + const data = (await response.json()) as UrlResponseTypes; + return data.url.OriginalUrl; + } else { + return null; // Return null if the response is not ok + } + } catch (error) { + console.error('Error fetching original URL:', error); + return null; // Return null in case of an error + } +} + +export default fetchOriginalUrl;