working mvp for tag selection. fails when not enough articles for a particular tag
This commit is contained in:
@@ -16,6 +16,8 @@ import { styled } from '@mui/material/styles';
|
|||||||
import SearchRoundedIcon from '@mui/icons-material/SearchRounded';
|
import SearchRoundedIcon from '@mui/icons-material/SearchRounded';
|
||||||
import RssFeedRoundedIcon from '@mui/icons-material/RssFeedRounded';
|
import RssFeedRoundedIcon from '@mui/icons-material/RssFeedRounded';
|
||||||
|
|
||||||
|
import { ArticleModel } from "../types/models";
|
||||||
|
|
||||||
|
|
||||||
const StyledCard = styled(Card)(({ theme }) => ({
|
const StyledCard = styled(Card)(({ theme }) => ({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@@ -119,6 +121,33 @@ export default function MainContent({
|
|||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [visibleArticles, setVisibleArticles] = React.useState<ArticleModel[]>(articles);
|
||||||
|
const [activeTag, setActiveTag] = React.useState<string | null>(null);
|
||||||
|
|
||||||
|
const filterArticlesByTag = (tag: string) => {
|
||||||
|
if (tag === 'all') {
|
||||||
|
// 🟢 Show all articles
|
||||||
|
setVisibleArticles(articles);
|
||||||
|
setActiveTag('all');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeTag === tag) {
|
||||||
|
// 🟡 Toggle off current tag → reset to all
|
||||||
|
setVisibleArticles(articles);
|
||||||
|
setActiveTag('all');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔵 Filter by selected tag
|
||||||
|
const filtered = articles.filter((article) => article.tag === tag);
|
||||||
|
console.log('👀 All Articles:', articles);
|
||||||
|
console.log(`👀 Filtered (${tag}):`, filtered);
|
||||||
|
|
||||||
|
setVisibleArticles(filtered);
|
||||||
|
setActiveTag(tag);
|
||||||
|
};
|
||||||
|
|
||||||
const handleFocus = (index: number) => {
|
const handleFocus = (index: number) => {
|
||||||
setFocusedCardIndex(index);
|
setFocusedCardIndex(index);
|
||||||
};
|
};
|
||||||
@@ -127,8 +156,9 @@ export default function MainContent({
|
|||||||
setFocusedCardIndex(null);
|
setFocusedCardIndex(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleTagClick = (tag: string) => {
|
||||||
console.info('You clicked the filter chip.');
|
setActiveTag((prev) => (prev === tag ? 'all' : tag));
|
||||||
|
filterArticlesByTag(tag)
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -171,41 +201,59 @@ export default function MainContent({
|
|||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Chip onClick={handleClick} size="medium" label="All categories" />
|
|
||||||
<Chip
|
<Chip
|
||||||
onClick={handleClick}
|
onClick={() => handleTagClick('all')}
|
||||||
size="medium"
|
size="medium"
|
||||||
label="Company"
|
label="All categories"
|
||||||
|
color={activeTag === 'all' ? 'primary' : 'default'}
|
||||||
|
variant={activeTag === 'all' ? 'filled' : 'outlined'}
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: 'transparent',
|
borderRadius: '8px',
|
||||||
border: 'none',
|
fontWeight: activeTag === 'all' ? 600 : 400,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Chip
|
<Chip
|
||||||
onClick={handleClick}
|
onClick={() => handleTagClick('infra')}
|
||||||
size="medium"
|
size="medium"
|
||||||
label="Product"
|
label="Infra"
|
||||||
|
color={activeTag === 'infra' ? 'primary' : 'default'}
|
||||||
|
variant={activeTag === 'infra' ? 'filled' : 'outlined'}
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: 'transparent',
|
borderRadius: '8px',
|
||||||
border: 'none',
|
fontWeight: activeTag === 'infra' ? 600 : 400,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Chip
|
<Chip
|
||||||
onClick={handleClick}
|
onClick={() => handleTagClick('code')}
|
||||||
size="medium"
|
size="medium"
|
||||||
label="Design"
|
label="Code"
|
||||||
|
color={activeTag === 'code' ? 'primary' : 'default'}
|
||||||
|
variant={activeTag === 'code' ? 'filled' : 'outlined'}
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: 'transparent',
|
borderRadius: '8px',
|
||||||
border: 'none',
|
fontWeight: activeTag === 'code' ? 600 : 400,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Chip
|
<Chip
|
||||||
onClick={handleClick}
|
onClick={() => handleTagClick('media')}
|
||||||
size="medium"
|
size="medium"
|
||||||
label="Engineering"
|
label="Media"
|
||||||
|
color={activeTag === 'media' ? 'primary' : 'default'}
|
||||||
|
variant={activeTag === 'media' ? 'filled' : 'outlined'}
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: 'transparent',
|
borderRadius: '8px',
|
||||||
border: 'none',
|
fontWeight: activeTag === 'media' ? 600 : 400,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Chip
|
||||||
|
onClick={() => handleTagClick('monitoring')}
|
||||||
|
size="medium"
|
||||||
|
label="Monitoring"
|
||||||
|
color={activeTag === 'monitoring' ? 'primary' : 'default'}
|
||||||
|
variant={activeTag === 'monitoring' ? 'filled' : 'outlined'}
|
||||||
|
sx={{
|
||||||
|
borderRadius: '8px',
|
||||||
|
fontWeight: activeTag === 'all' ? 600 : 400,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -237,7 +285,7 @@ export default function MainContent({
|
|||||||
<CardMedia
|
<CardMedia
|
||||||
component="img"
|
component="img"
|
||||||
alt="green iguana"
|
alt="green iguana"
|
||||||
image={articles[0].img}
|
image={visibleArticles[0].img}
|
||||||
sx={{
|
sx={{
|
||||||
aspectRatio: '16 / 9',
|
aspectRatio: '16 / 9',
|
||||||
borderBottom: '1px solid',
|
borderBottom: '1px solid',
|
||||||
@@ -246,16 +294,16 @@ export default function MainContent({
|
|||||||
/>
|
/>
|
||||||
<StyledCardContent>
|
<StyledCardContent>
|
||||||
<Typography gutterBottom variant="caption" component="div">
|
<Typography gutterBottom variant="caption" component="div">
|
||||||
{articles[0].tag}
|
{visibleArticles[0].tag}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography gutterBottom variant="h6" component="div">
|
<Typography gutterBottom variant="h6" component="div">
|
||||||
{articles[0].title}
|
{visibleArticles[0].title}
|
||||||
</Typography>
|
</Typography>
|
||||||
<StyledTypography variant="body2" color="text.secondary" gutterBottom>
|
<StyledTypography variant="body2" color="text.secondary" gutterBottom>
|
||||||
{articles[0].description}
|
{visibleArticles[0].description}
|
||||||
</StyledTypography>
|
</StyledTypography>
|
||||||
</StyledCardContent>
|
</StyledCardContent>
|
||||||
<Author authors={articles[0].authors} />
|
<Author authors={visibleArticles[0].authors} />
|
||||||
</StyledCard>
|
</StyledCard>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid size={{ xs: 12, md: 6 }}>
|
<Grid size={{ xs: 12, md: 6 }}>
|
||||||
@@ -270,7 +318,7 @@ export default function MainContent({
|
|||||||
<CardMedia
|
<CardMedia
|
||||||
component="img"
|
component="img"
|
||||||
alt="green iguana"
|
alt="green iguana"
|
||||||
image={articles[1].img}
|
image={visibleArticles[1].img}
|
||||||
aspect-ratio="16 / 9"
|
aspect-ratio="16 / 9"
|
||||||
sx={{
|
sx={{
|
||||||
borderBottom: '1px solid',
|
borderBottom: '1px solid',
|
||||||
@@ -279,16 +327,16 @@ export default function MainContent({
|
|||||||
/>
|
/>
|
||||||
<StyledCardContent>
|
<StyledCardContent>
|
||||||
<Typography gutterBottom variant="caption" component="div">
|
<Typography gutterBottom variant="caption" component="div">
|
||||||
{articles[1].tag}
|
{visibleArticles[1].tag}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography gutterBottom variant="h6" component="div">
|
<Typography gutterBottom variant="h6" component="div">
|
||||||
{articles[1].title}
|
{visibleArticles[1].title}
|
||||||
</Typography>
|
</Typography>
|
||||||
<StyledTypography variant="body2" color="text.secondary" gutterBottom>
|
<StyledTypography variant="body2" color="text.secondary" gutterBottom>
|
||||||
{articles[1].description}
|
{visibleArticles[1].description}
|
||||||
</StyledTypography>
|
</StyledTypography>
|
||||||
</StyledCardContent>
|
</StyledCardContent>
|
||||||
<Author authors={articles[1].authors} />
|
<Author authors={visibleArticles[1].authors} />
|
||||||
</StyledCard>
|
</StyledCard>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid size={{ xs: 12, md: 4 }}>
|
<Grid size={{ xs: 12, md: 4 }}>
|
||||||
@@ -304,7 +352,7 @@ export default function MainContent({
|
|||||||
<CardMedia
|
<CardMedia
|
||||||
component="img"
|
component="img"
|
||||||
alt="green iguana"
|
alt="green iguana"
|
||||||
image={articles[2].img}
|
image={visibleArticles[2].img}
|
||||||
sx={{
|
sx={{
|
||||||
height: { sm: 'auto', md: '50%' },
|
height: { sm: 'auto', md: '50%' },
|
||||||
aspectRatio: { sm: '16 / 9', md: '' },
|
aspectRatio: { sm: '16 / 9', md: '' },
|
||||||
@@ -312,16 +360,16 @@ export default function MainContent({
|
|||||||
/>
|
/>
|
||||||
<StyledCardContent>
|
<StyledCardContent>
|
||||||
<Typography gutterBottom variant="caption" component="div">
|
<Typography gutterBottom variant="caption" component="div">
|
||||||
{articles[2].tag}
|
{visibleArticles[2].tag}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography gutterBottom variant="h6" component="div">
|
<Typography gutterBottom variant="h6" component="div">
|
||||||
{articles[2].title}
|
{visibleArticles[2].title}
|
||||||
</Typography>
|
</Typography>
|
||||||
<StyledTypography variant="body2" color="text.secondary" gutterBottom>
|
<StyledTypography variant="body2" color="text.secondary" gutterBottom>
|
||||||
{articles[2].description}
|
{visibleArticles[2].description}
|
||||||
</StyledTypography>
|
</StyledTypography>
|
||||||
</StyledCardContent>
|
</StyledCardContent>
|
||||||
<Author authors={articles[2].authors} />
|
<Author authors={visibleArticles[2].authors} />
|
||||||
</StyledCard>
|
</StyledCard>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid size={{ xs: 12, md: 4 }}>
|
<Grid size={{ xs: 12, md: 4 }}>
|
||||||
@@ -347,21 +395,21 @@ export default function MainContent({
|
|||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<Typography gutterBottom variant="caption" component="div">
|
<Typography gutterBottom variant="caption" component="div">
|
||||||
{articles[3].tag}
|
{visibleArticles[3].tag}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography gutterBottom variant="h6" component="div">
|
<Typography gutterBottom variant="h6" component="div">
|
||||||
{articles[3].title}
|
{visibleArticles[3].title}
|
||||||
</Typography>
|
</Typography>
|
||||||
<StyledTypography
|
<StyledTypography
|
||||||
variant="body2"
|
variant="body2"
|
||||||
color="text.secondary"
|
color="text.secondary"
|
||||||
gutterBottom
|
gutterBottom
|
||||||
>
|
>
|
||||||
{articles[3].description}
|
{visibleArticles[3].description}
|
||||||
</StyledTypography>
|
</StyledTypography>
|
||||||
</div>
|
</div>
|
||||||
</StyledCardContent>
|
</StyledCardContent>
|
||||||
<Author authors={articles[3].authors} />
|
<Author authors={visibleArticles[3].authors} />
|
||||||
</StyledCard>
|
</StyledCard>
|
||||||
<StyledCard
|
<StyledCard
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@@ -382,21 +430,21 @@ export default function MainContent({
|
|||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<Typography gutterBottom variant="caption" component="div">
|
<Typography gutterBottom variant="caption" component="div">
|
||||||
{articles[4].tag}
|
{visibleArticles[4].tag}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography gutterBottom variant="h6" component="div">
|
<Typography gutterBottom variant="h6" component="div">
|
||||||
{articles[4].title}
|
{visibleArticles[4].title}
|
||||||
</Typography>
|
</Typography>
|
||||||
<StyledTypography
|
<StyledTypography
|
||||||
variant="body2"
|
variant="body2"
|
||||||
color="text.secondary"
|
color="text.secondary"
|
||||||
gutterBottom
|
gutterBottom
|
||||||
>
|
>
|
||||||
{articles[4].description}
|
{visibleArticles[4].description}
|
||||||
</StyledTypography>
|
</StyledTypography>
|
||||||
</div>
|
</div>
|
||||||
</StyledCardContent>
|
</StyledCardContent>
|
||||||
<Author authors={articles[4].authors} />
|
<Author authors={visibleArticles[4].authors} />
|
||||||
</StyledCard>
|
</StyledCard>
|
||||||
</Box>
|
</Box>
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -413,7 +461,7 @@ export default function MainContent({
|
|||||||
<CardMedia
|
<CardMedia
|
||||||
component="img"
|
component="img"
|
||||||
alt="green iguana"
|
alt="green iguana"
|
||||||
image={articles[5].img}
|
image={visibleArticles[5].img}
|
||||||
sx={{
|
sx={{
|
||||||
height: { sm: 'auto', md: '50%' },
|
height: { sm: 'auto', md: '50%' },
|
||||||
aspectRatio: { sm: '16 / 9', md: '' },
|
aspectRatio: { sm: '16 / 9', md: '' },
|
||||||
@@ -421,16 +469,16 @@ export default function MainContent({
|
|||||||
/>
|
/>
|
||||||
<StyledCardContent>
|
<StyledCardContent>
|
||||||
<Typography gutterBottom variant="caption" component="div">
|
<Typography gutterBottom variant="caption" component="div">
|
||||||
{articles[5].tag}
|
{visibleArticles[5].tag}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography gutterBottom variant="h6" component="div">
|
<Typography gutterBottom variant="h6" component="div">
|
||||||
{articles[5].title}
|
{visibleArticles[5].title}
|
||||||
</Typography>
|
</Typography>
|
||||||
<StyledTypography variant="body2" color="text.secondary" gutterBottom>
|
<StyledTypography variant="body2" color="text.secondary" gutterBottom>
|
||||||
{articles[5].description}
|
{visibleArticles[5].description}
|
||||||
</StyledTypography>
|
</StyledTypography>
|
||||||
</StyledCardContent>
|
</StyledCardContent>
|
||||||
<Author authors={articles[5].authors} />
|
<Author authors={visibleArticles[5].authors} />
|
||||||
</StyledCard>
|
</StyledCard>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export const ArticleProvider: React.FC<{ children: React.ReactNode }> = ({ child
|
|||||||
const [articles, setArticles] = useState<ArticleModel[]>([]);
|
const [articles, setArticles] = useState<ArticleModel[]>([]);
|
||||||
const [loading, setLoading] = useState<boolean>(true);
|
const [loading, setLoading] = useState<boolean>(true);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const { token } = useAuth(); // ✅ access token if needed
|
const { token } = useAuth();
|
||||||
|
|
||||||
/** 🔹 Fetch articles (JWT automatically attached by api.ts interceptor) */
|
/** 🔹 Fetch articles (JWT automatically attached by api.ts interceptor) */
|
||||||
const fetchArticles = async () => {
|
const fetchArticles = async () => {
|
||||||
@@ -18,7 +18,7 @@ export const ArticleProvider: React.FC<{ children: React.ReactNode }> = ({ child
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
const res = await api.get<ArticleModel[]>('/articles', { params: { skip: 0, limit: 10 } });
|
const res = await api.get<ArticleModel[]>('/articles', { params: { skip: 0, limit: 100 } });
|
||||||
const formatted = res.data.map((a) => ({ ...a, id: a._id || undefined }));
|
const formatted = res.data.map((a) => ({ ...a, id: a._id || undefined }));
|
||||||
setArticles(formatted);
|
setArticles(formatted);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
|
|||||||
Reference in New Issue
Block a user