Skip to content

Commit

Permalink
added fallback data for articles and tags in case API doesn' work pro…
Browse files Browse the repository at this point in the history
…perly
  • Loading branch information
nina1012 committed Oct 29, 2024
1 parent aac7ef9 commit 99c3c00
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 37 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ Simply log in with these credentials to start using the application. 🚀

## Important Notice ⚠️

**Please note:** The app may not render or function correctly if the API (https://api.realworld.io/api/) is down or experiencing issues. This could affect features such as user authentication, data fetching, and any dynamic content relying on the backend.
**Please note:** The app may not render or function correctly if the API (https://api.realworld.io/api/) is down or experiencing issues. This could affect features such as user authentication, data fetching, and any dynamic content relying on the backend. To demonstrate the functionality of the application, I have included several demo Articles and Tags. These are designed to showcase the core features of the app, even if the API is not working properly or is unavailable.

If you encounter problems:

Expand Down
Binary file added public/avatar-placeholder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
72 changes: 40 additions & 32 deletions src/features/articles/api/get-articles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { apiClient } from '@/lib/api-client';
import { useQuery } from '@tanstack/react-query';
import { ArticlesType } from '../types';
import storage from '@/utils/storage';
import { demoArticles } from '../demoData';

// Get most recent articles globally. Use query parameters to filter results. Auth is optional
export const getArticles = (
export const getArticles = async (
tag?: string,
author?: string,
page?: number
Expand All @@ -14,40 +15,47 @@ export const getArticles = (
// get articles by author
const user = storage.getUser()?.user;

if (author) {
return apiClient.get(
`${BASE_URL_API}/articles?author=${encodeURIComponent(
author
)}&offset=${page}&limit=${LIMIT}`,
user && {
headers: {
Authorization: `Token ${user && user.token}`,
},
}
);
}
try {
let response;
if (author) {
response = await apiClient.get(
`${BASE_URL_API}/articles?author=${encodeURIComponent(
author
)}&offset=${page}&limit=${LIMIT}`,
user && {
headers: {
Authorization: `Token ${user && user.token}`,
},
}
);
} else if (tag) {
response = await apiClient.get(
`${BASE_URL_API}/articles?tag=${tag}&offset=${page}&limit=${LIMIT}`,
user && {
headers: {
Authorization: `Token ${user && user.token}`,
},
}
);
} else {
response = await apiClient.get(
`${BASE_URL_API}/articles?&offset=${page}&limit=${LIMIT}`,
user && {
headers: {
Authorization: `Token ${user?.token}`,
},
}
);
}

// get articles by tags
if (tag) {
return apiClient.get(
`${BASE_URL_API}/articles?tag=${tag}&offset=${page}&limit=${LIMIT}`,
user && {
headers: {
Authorization: `Token ${user && user.token}`,
},
}
return response.data;
} catch (error) {
console.error(
'API is down, serving demo articles:',
error
);
return demoArticles as ArticlesType; // Fallback to demo articles
}

// global articles
return apiClient.get(
`${BASE_URL_API}/articles?&offset=${page}&limit=${LIMIT}`,
user && {
headers: {
Authorization: `Token ${user?.token}`,
},
}
);
};

export const useArticles = (
Expand Down
11 changes: 11 additions & 0 deletions src/features/articles/components/ArticleList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import ArticlePreview from './ArticlePreview';
import { Conditional } from '@/components/common/Conditional';
import Pagination from '@/components/common/Pagination';
import { usePagination } from '@/stores/pagination';
import { demoArticles } from '../demoData';
import { GoInfo } from 'react-icons/go';

const ArticleList = () => {
const router = useRouter();
Expand Down Expand Up @@ -33,6 +35,15 @@ const ArticleList = () => {
</div>
) : (
<>
{articles === demoArticles && (
<div className="banner my-2 flex gap-2 items-center justify-center bg-red-100 text-red-800 p-4 rounded-md shadow-md mb-4">
<GoInfo size={20} />
<p className="text-sm font-medium">
You&apos;re viewing sample articles as the
service is temporarily unavailable.
</p>
</div>
)}
{articles?.articlesCount ? (
<div className="mb-12">
{articles?.articles?.map((article) => {
Expand Down
99 changes: 99 additions & 0 deletions src/features/articles/demoData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { ArticlesType } from './types/index';

export const demoArticles: ArticlesType = {
articles: [
{
slug: 'demo-article-1',
title:
'Understanding Fallbacks in React Applications',
description:
'Learn how to create robust fallback data handling.',
body: 'This is a sample article content for demo purposes.',
tagList: ['React', 'Fallback'],
createdAt: new Date('2023-10-01T10:00:00Z'),
updatedAt: new Date('2023-10-01T10:00:00Z'),
favorited: false,
favoritesCount: 10,
author: {
username: 'nina1012',
bio: 'Demo author bio',
image: '/avatar-placeholder.png',
following: true,
},
},
{
slug: 'advanced-css-tips',
title: 'Advanced CSS Tips and Tricks',
description:
'Take your CSS skills to the next level with these pro tips.',
body: 'CSS is not just for simple styling. With advanced techniques like CSS Grid, animations, and custom properties, you can create complex layouts and stunning visual effects...',
tagList: ['CSS', 'Web Design', 'Frontend'],
createdAt: new Date('2023-08-22T09:15:00Z'),
updatedAt: new Date('2023-08-22T09:15:00Z'),
favorited: true,
favoritesCount: 57,
author: {
username: 'css_master',
bio: 'Front-end developer focused on styling and design.',
image: '/avatar-placeholder.png',
following: true,
},
},
{
slug: 'javascript-async-await',
title: 'Mastering Async/Await in JavaScript',
description:
'Learn how to handle asynchronous code in JavaScript with async/await.',
body: 'Asynchronous programming is essential in JavaScript for handling tasks like API requests. With async/await, writing async code becomes much more readable and maintainable...',
tagList: ['JavaScript', 'Async Programming', 'ES6'],
createdAt: new Date('2023-06-18T14:30:00Z'),
updatedAt: new Date('2023-06-18T14:30:00Z'),
favorited: false,
favoritesCount: 46,
author: {
username: 'js_pro',
bio: 'JavaScript enthusiast sharing coding insights.',
image: '/avatar-placeholder.png',
following: false,
},
},
{
slug: 'introduction-to-supabase',
title:
'Introduction to Supabase: The Open Source Firebase Alternative',
description:
'A deep dive into Supabase and how it powers modern applications.',
body: 'Supabase offers real-time databases, authentication, and storage, making it a great choice for modern app development. In this article, we explore its core features...',
tagList: ['Supabase', 'Backend', 'Database'],
createdAt: new Date('2023-09-01T08:45:00Z'),
updatedAt: new Date('2023-09-01T08:45:00Z'),
favorited: true,
favoritesCount: 64,
author: {
username: 'data_wizard',
bio: 'Back-end developer fascinated by databases and cloud solutions.',
image: '/avatar-placeholder.png',
following: true,
},
},
{
slug: 'web-accessibility-guide',
title: 'Creating Accessible Web Applications',
description:
'Make your web applications accessible to everyone with these techniques.',
body: 'Web accessibility is vital for ensuring that all users, including those with disabilities, can use your application. This article covers essential techniques like ARIA roles, keyboard navigation, and color contrast...',
tagList: ['Accessibility', 'Frontend', 'UX'],
createdAt: new Date('2023-10-05T17:00:00Z'),
updatedAt: new Date('2023-10-05T17:00:00Z'),
favorited: false,
favoritesCount: 42,
author: {
username: 'accessibility_advocate',
bio: 'UX designer promoting inclusive web practices.',
image: '/avatar-placeholder.png',
following: false,
},
},
],
articlesCount: 5,
};
18 changes: 14 additions & 4 deletions src/features/tags/api/get-tags.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
import { BASE_URL_API } from '@/config/constants';
import { apiClient } from '@/lib/api-client';
import { useQuery } from '@tanstack/react-query';
import { demoTags } from '../demoData';

type Tags = {
tags: string[] | null;
};

export const getTags = () => {
return apiClient.get<Tags, { tags: [] }>(
`${BASE_URL_API}/tags`
);
export const getTags = async () => {
try {
const response = await apiClient.get<
Tags,
{ tags: string[] }
>(`${BASE_URL_API}/tags`);
return response;
} catch (error) {
console.warn(
'API is down. Using demo tags as fallback.'
);
return { tags: demoTags };
}
};

export const useTags = () => {
Expand Down
11 changes: 11 additions & 0 deletions src/features/tags/components/Tags.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import Spinner from '@/components/common/Spinner';
import { Link } from '@/components/link/Link';
import { useTags } from '@/features/tags';
import { demoTags } from '../demoData';
import { GoInfo } from 'react-icons/go';

type TagsProps = {
articleTags?: string[];
Expand Down Expand Up @@ -29,6 +31,15 @@ const Tags = ({ articleTags }: TagsProps) => {
return (
<div className="tags-container relative w-full md:flex-[0_0_25%] min-h-[160px] bg-zinc-100 px-3 py-3 rounded-md ml-auto">
<p className="mb-4 text-md">Popular tags</p>
{tags === demoTags && (
<div className="banner my-2 gap-2 flex items-center justify-center bg-red-100 text-red-800 p-4 rounded-md shadow-md mb-4">
<GoInfo size={40} />
<p className="text-xs font-medium">
You&apos;re viewing sample tags as the service
is temporarily unavailable.
</p>
</div>
)}
<div className="flex flex-wrap h-full w-full">
{isLoading && (
<Spinner
Expand Down
11 changes: 11 additions & 0 deletions src/features/tags/demoData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const demoTags = [
'React',
'Fallback',
'CSS',
'Web Design',
'Frontend',
'JavaScript',
'ES6',
'Backend',
'Accessibility',
];

0 comments on commit 99c3c00

Please sign in to comment.