implement tanstack and fetch all data

This commit is contained in:
rahat0078
2026-04-04 22:49:48 +06:00
parent d71b4ab17e
commit d96ab17169
26 changed files with 394 additions and 107 deletions
+4 -4
View File
@@ -11,12 +11,12 @@ import ProjectDetails from "./pages/ProjectDetails";
import Blog from "./pages/Blog";
import BlogArticle from "./pages/BlogArticle";
import NotFound from "./pages/NotFound";
import { QueryProvider } from "./provider/QueryProvider";
const queryClient = new QueryClient();
function AnimatedRoutes() {
const location = useLocation();
return (
<AnimatePresence mode="wait">
<Routes location={location} key={location.pathname}>
@@ -33,7 +33,7 @@ function AnimatedRoutes() {
}
const App = () => (
<QueryClientProvider client={queryClient}>
<QueryProvider>
<ThemeProvider>
<TooltipProvider>
<Toaster />
@@ -43,7 +43,7 @@ const App = () => (
</BrowserRouter>
</TooltipProvider>
</ThemeProvider>
</QueryClientProvider>
</QueryProvider>
);
export default App;
+11
View File
@@ -0,0 +1,11 @@
import axios from "axios";
const axiosInstance = axios.create({
baseURL: import.meta.env.VITE_API_URL,
timeout: 5000,
headers: {
"Content-Type": "application/json",
},
});
export default axiosInstance;
+24
View File
@@ -0,0 +1,24 @@
import { T_blogs } from "@/types/blogs.type";
import axiosInstance from "../axiosInstance";
export interface IBlogQueryParams {
[key: string]: string | number | boolean | undefined;
}
export const blogService = {
getBlogs: (params?: IBlogQueryParams) =>
axiosInstance.get("/api/blogs", { params }).then(res => res.data),
getBlogById: (id: string) =>
axiosInstance.get(`/api/blogs/${id}`),
createBlog: (data: Partial<T_blogs>) =>
axiosInstance.post("/api/blogs", data),
updateBlog: (id: string, data: Partial<T_blogs>) =>
axiosInstance.patch(`/api/blogs/${id}`, data),
deleteBlog: (id: string) =>
axiosInstance.delete(`/api/blogs/${id}`),
};
+24
View File
@@ -0,0 +1,24 @@
import { T_projects } from '@/types/projects.type';
import axiosInstance from './../axiosInstance';
export interface IProjectsQueryParams {
[key: string]: string | number | boolean | undefined;
}
export const projectsService = {
getProjects: (params?: IProjectsQueryParams) =>
axiosInstance.get("/api/projects", { params }),
getProjectById: (id: string) =>
axiosInstance.get(`/api/projects/${id}`),
createProject: (data: Partial<T_projects>) =>
axiosInstance.post("/api/projects", data),
updateProject: (id: string, data: Partial<T_projects>) =>
axiosInstance.patch(`/api/projects/${id}`, data),
deleteProject: (id: string) =>
axiosInstance.delete(`/api/projects/${id}`),
};
+20
View File
@@ -0,0 +1,20 @@
import { T_reviews } from '@/types/review.type';
import axiosInstance from './../axiosInstance';
export const reviewsService = {
getReviews: () =>
axiosInstance.get("/api/reviews"),
getReviewById: (id: string) =>
axiosInstance.get(`/api/reviews/${id}`),
createReview: (data: Partial<T_reviews>) =>
axiosInstance.post("/api/reviews", data),
updateReview: (id: string, data: Partial<T_reviews>) =>
axiosInstance.patch(`/api/reviews/${id}`, data),
deleteReview: (id: string) =>
axiosInstance.delete(`/api/reviews/${id}`),
};
+19
View File
@@ -0,0 +1,19 @@
import { T_team } from '@/types/team.type';
import axiosInstance from './../axiosInstance';
export const teamService = {
getTeams: () =>
axiosInstance.get("/api/team"),
getTeamById: (id: string) =>
axiosInstance.get(`/api/team/${id}`),
createTeam: (data: Partial<T_team>) =>
axiosInstance.post("/api/team", data),
updateTeam: (id: string, data: Partial<T_team>) =>
axiosInstance.patch(`/api/team/${id}`, data),
deleteTeam: (id: string) =>
axiosInstance.delete(`/api/team/${id}`),
};
+10 -63
View File
@@ -8,72 +8,19 @@ import { Swiper, SwiperSlide } from "swiper/react";
// Import Swiper styles
import "swiper/css";
import "swiper/css/pagination";
import { useTeam } from "@/hooks/queires/useTeam";
const team = [
// {
// name: "Md Abumahid Islam",
// role: "CEO & Founder",
// image:
// "https://res.cloudinary.com/dnxsk9rgl/image/upload/v1772734622/abumahid_ghax5c.png",
// bio: "Visionary founder building innovative digital technology solutions.",
// github: "https://github.com/abumahid",
// twitter: "https://x.com/Abumahidislam",
// linkedin: "https://www.linkedin.com/in/md-abu-mahid-islam",
// },
{
name: "Rimi Rahman",
role: "Front-end Developer",
image:
"https://res.cloudinary.com/dnxsk9rgl/image/upload/v1772735809/rimi_easbn4.png",
bio: "Technology leader designing scalable and reliable software systems.",
github: "https://github.com/sanjidaRimi023",
twitter: "",
linkedin: "https://www.linkedin.com/in/sanjidarimi023/",
},
{
name: "Utsob Saha",
role: "Social Media Manager",
image:
"https://res.cloudinary.com/dnxsk9rgl/image/upload/v1772733893/utsob_txy0qe.png",
bio: "Driving brand growth through creative social media strategy.",
github: "https://github.com/Utsob1621",
twitter: "",
linkedin: "https://www.linkedin.com/in/utsob-saha-211894350/",
},
{
name: "Yeassin Ali",
role: "Front-end Developer",
image:
"https://res.cloudinary.com/dnxsk9rgl/image/upload/v1772735363/yeassing_pf6ta6.png",
bio: "Frontend specialist creating fast and responsive web interfaces.",
github: "https://github.com/Yeassin7376",
twitter: "",
linkedin: "https://www.linkedin.com/in/yeassin-ali17/",
},
{
name: "Sharafat Hossain",
role: "Front-end Developer",
image:
"https://res.cloudinary.com/dnxsk9rgl/image/upload/v1772736523/sharafat_pydaih.png",
bio: "Building modern web applications with full stack expertise.",
github: "https://github.com/dev-sharafat",
twitter: "",
linkedin: "https://www.linkedin.com/in/sharafathassain23/",
},
{
name: "Ripa Akter Badhon",
role: "HR Manager",
image:
"https://res.cloudinary.com/dnxsk9rgl/image/upload/v1772991488/badhon_ny4nsr.png",
bio: "Supporting team growth and employee wellbeing.",
github: "",
twitter: "",
linkedin: "",
},
];
export default function TeamSection() {
const {data: teamdata} = useTeam();
const team = teamdata?.data.data;
const ref = useRef<HTMLElement>(null);
const isInView = useInView(ref, { once: true, margin: "-100px" });
const shouldScroll = team.length >= 5;
+2
View File
@@ -540,6 +540,8 @@ LLMs are powerful tools, but they require thoughtful implementation. Start with
},
];
export const getPostBySlug = (slug: string): BlogPost | undefined => {
return blogPosts.find(post => post.slug === slug);
};
+12
View File
@@ -0,0 +1,12 @@
export enum BlogCategory {
WEB_DEVELOPMENT = "Web Development",
MOBILE_DEVELOPMENT = "Mobile Development",
UI_UX_DESIGN = "UI/UX Design",
DEVOPS = "DevOps",
MACHINE_LEARNING = "Machine Learning",
CYBER_SECURITY = "Cyber Security",
CLOUD_COMPUTING = "Cloud Computing",
DATA_SCIENCE = "Data Science",
PROGRAMMING = "Programming",
CAREER_GUIDE = "Career Guide",
}
+5
View File
@@ -0,0 +1,5 @@
export enum BlogStatus {
PUBLISHED = "PUBLISHED",
DRAFT = "DRAFT",
ARCHIVED = "ARCHIVED"
}
+17
View File
@@ -0,0 +1,17 @@
export enum ProjectCategory {
WEB = "web",
MOBILE = "mobile",
DESKTOP = "desktop",
BACKEND = "backend",
FULLSTACK = "fullstack",
CLOUD = "cloud",
AI = "ai",
MACHINE_LEARNING = "machine-learning",
DATA_SCIENCE = "data-science",
DEVOPS = "devops",
ECOMMERCE = "ecommerce",
SAAS = "saas",
API = "api",
BLOCKCHAIN = "blockchain",
IOT = "iot"
}
+5
View File
@@ -0,0 +1,5 @@
export enum ProjectStatus {
COMPLETED = "completed",
ONGOING = "ongoing",
ARCHIVED = "archived"
}
+19
View File
@@ -0,0 +1,19 @@
import { blogService, IBlogQueryParams } from "@/api/services/blog.service";
import { queryKeys } from "@/utils/queryKeys";
import { useQuery } from "@tanstack/react-query";
export const useBlogs = (params?: IBlogQueryParams) => {
return useQuery({
queryKey: [...queryKeys.blogs, params],
queryFn: () => blogService.getBlogs(params),
});
};
export const useBlogById = (id: string) => {
return useQuery({
queryKey: queryKeys.blog(id),
queryFn: () => blogService.getBlogById(id),
enabled: !!id,
});
};
+19
View File
@@ -0,0 +1,19 @@
import { IProjectsQueryParams, projectsService } from "@/api/services/project.service";
import { queryKeys } from "@/utils/queryKeys";
import { useQuery } from "@tanstack/react-query";
export const useProjects = (params?: IProjectsQueryParams) => {
return useQuery({
queryKey: [...queryKeys.projects, params],
queryFn: () => projectsService.getProjects(params),
});
};
export const useProjectById = (id: string) => {
return useQuery({
queryKey: queryKeys.project(id),
queryFn: () => projectsService.getProjectById(id),
enabled: !!id,
});
};
+11
View File
@@ -0,0 +1,11 @@
import { reviewsService } from "@/api/services/review.service";
import { queryKeys } from "@/utils/queryKeys";
import { useQuery } from "@tanstack/react-query";
export const useReviews = () => {
return useQuery({
queryKey: [...queryKeys.reviews],
queryFn: () => reviewsService.getReviews(),
});
};
+11
View File
@@ -0,0 +1,11 @@
import { teamService } from "@/api/services/team.service";
import { queryKeys } from "@/utils/queryKeys";
import { useQuery } from "@tanstack/react-query";
export const useTeam = () => {
return useQuery({
queryKey: [...queryKeys.team],
queryFn: () => teamService.getTeams(),
});
};
+11 -6
View File
@@ -8,6 +8,7 @@ import Navbar from '@/components/Navbar';
import Footer from '@/components/Footer';
import PageTransition from '@/components/PageTransition';
import { blogPosts } from '@/data/blogData';
import { useBlogs } from './../hooks/queires/useBlogs';
const categories = ['All', 'AI & Machine Learning', 'Cloud Solutions', 'Web Development', 'Mobile Development'];
@@ -29,13 +30,18 @@ const itemVariants = {
};
export default function Blog() {
const [activeCategory, setActiveCategory] = useState('All');
const [searchQuery, setSearchQuery] = useState('');
const filteredPosts = blogPosts.filter(post => {
const matchesCategory = activeCategory === 'All' || post.category === activeCategory;
const matchesSearch = post.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
post.excerpt.toLowerCase().includes(searchQuery.toLowerCase());
post.excerpt.toLowerCase().includes(searchQuery.toLowerCase());
return matchesCategory && matchesSearch;
});
@@ -110,11 +116,10 @@ export default function Blog() {
key={category}
variant={activeCategory === category ? 'default' : 'outline'}
onClick={() => setActiveCategory(category)}
className={`rounded-full px-6 transition-all duration-300 ${
activeCategory === category
? 'neon-glow bg-primary text-primary-foreground'
: 'glass border-primary/30 hover:border-primary'
}`}
className={`rounded-full px-6 transition-all duration-300 ${activeCategory === category
? 'neon-glow bg-primary text-primary-foreground'
: 'glass border-primary/30 hover:border-primary'
}`}
>
{category}
</Button>
+12 -7
View File
@@ -7,6 +7,10 @@ import Navbar from '@/components/Navbar';
import Footer from '@/components/Footer';
import PageTransition from '@/components/PageTransition';
import { projects } from '@/data/projectData';
import { useBlogById, useBlogs } from './../hooks/queires/useBlogs';
import { useProjectById, useProjects } from '@/hooks/queires/useProjects';
import { useTeam } from '@/hooks/queires/useTeam';
import { useReviews } from '@/hooks/queires/useReviews';
const categories = [
{ id: 'all', name: 'All Projects', icon: null },
@@ -36,6 +40,8 @@ const itemVariants = {
};
export default function Projects() {
const [activeCategory, setActiveCategory] = useState('all');
const filteredProjects = activeCategory === 'all'
@@ -46,7 +52,7 @@ export default function Projects() {
<PageTransition>
<div className="min-h-screen bg-background overflow-x-hidden">
<Navbar />
{/* Hero Section */}
<section className="pt-32 pb-16 relative overflow-hidden">
<div className="absolute inset-0">
@@ -98,11 +104,10 @@ export default function Projects() {
key={category.id}
variant={activeCategory === category.id ? 'default' : 'outline'}
onClick={() => setActiveCategory(category.id)}
className={`rounded-full px-6 transition-all duration-300 ${
activeCategory === category.id
? 'neon-glow bg-primary text-primary-foreground'
: 'glass border-primary/30 hover:border-primary'
}`}
className={`rounded-full px-6 transition-all duration-300 ${activeCategory === category.id
? 'neon-glow bg-primary text-primary-foreground'
: 'glass border-primary/30 hover:border-primary'
}`}
>
{Icon && <Icon className="w-4 h-4 mr-2" />}
{category.name}
@@ -140,7 +145,7 @@ export default function Projects() {
className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110"
/>
<div className="absolute inset-0 bg-gradient-to-t from-background via-background/50 to-transparent opacity-60" />
{/* Category Badge */}
<div className="absolute top-4 left-4">
<span className="px-3 py-1 rounded-full bg-primary/20 text-primary text-sm font-medium backdrop-blur-sm border border-primary/30">
+20
View File
@@ -0,0 +1,20 @@
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ReactNode } from "react";
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 5,
refetchOnWindowFocus: false,
retry: 1,
},
},
});
export const QueryProvider = ({ children }: { children: ReactNode }) => {
return (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
);
};
+30
View File
@@ -0,0 +1,30 @@
import { BlogCategory } from "@/enums/blogCategory";
import { BlogStatus } from "@/enums/blogStatus";
export type T_socialLinks = {
github: string;
linkedin?: string;
twitter?: string;
portfolio?: string;
facebook?: string;
}
export type T_blogs = {
title: string;
content_description: string;
thumbnail: string;
images?: string[];
authorName: string;
authorImage: string;
authorDesignation: string;
authorEmail: string;
socialMediaLink: T_socialLinks;
category: BlogCategory;
tags: string[];
isFeatured: boolean;
status: BlogStatus;
createdAt: Date;
updatedAt: Date;
}
+19
View File
@@ -0,0 +1,19 @@
import { ProjectCategory } from "@/enums/projectCategory";
import { ProjectStatus } from "@/enums/projectStatus";
export type T_projects = {
name: string;
description: string;
thumbnail?: string;
images?: string[];
category: ProjectCategory;
githubLink: string;
liveLink?: string;
technologies: string[];
companyName: string;
completionYear?: number;
isFeatured: boolean;
status: ProjectStatus;
createdAt: Date;
updatedAt: Date;
}
+8
View File
@@ -0,0 +1,8 @@
export type T_reviews = {
rating: number;
review: string;
client_name: string;
thumbnail: string;
designation: string;
verified_link: string;
}
+17
View File
@@ -0,0 +1,17 @@
export type T_social_links = {
github: string;
linkedin?: string;
twitter?: string;
portfolio?: string;
facebook?: string;
}
export type T_team = {
name: string;
role: string;
description: string;
image: string;
socialLinks: T_social_links;
createdAt: Date;
updatedAt: Date;
}
+13
View File
@@ -0,0 +1,13 @@
export const queryKeys = {
blogs: ["blogs"],
blog: (id: string) => ["blogs", id],
projects: ["projects"],
project: (id: string) => ["projects", id],
reviews: ["reviews"],
review: (id: string) => ["reviews", id],
team: ["team"],
member: (id: string) => ["team", id],
};