update 26/03

This commit is contained in:
2025-03-26 13:18:49 +07:00
parent cc8b18bbc9
commit 306a9de89b
11 changed files with 880 additions and 977 deletions

View File

@@ -14,7 +14,9 @@ const ArticleDetail = () => {
if (typeof slug === "string") {
const getArticleDetail = async () => {
const data = await fetchArticleDetail(slug);
if (Array.isArray(data) && data.length > 0) {
setArticleDetails(data[0]);
}
};
getArticleDetail();
}

View File

@@ -1,9 +1,8 @@
"use client";
import { Suspense, useEffect, useState } from "react";
import { format } from "date-fns";
import Link from "next/link";
import { ArticleListDataType } from "@/types/article";
import { fetchListArticles } from "@/api/apiService";
import ArticleItem from "@/components/articles/ArticleItem"; // Import ArticleItem component
import { ArticleListDataType } from "@/types/article";
const HomeArticle = () => {
const [articleList, setArticleList] = useState<ArticleListDataType | null>(
@@ -13,27 +12,31 @@ const HomeArticle = () => {
useEffect(() => {
const fetchArticleList = async () => {
try {
const data = await fetchListArticles();
setArticleList(data.list);
} catch (error) {
console.error("Failed to fetch articles:", error);
} finally {
setLoadingUI(false);
}
};
fetchArticleList();
}, []);
return (
<Suspense>
{loadingUi ? (
<div className="page-article">
<div className="container">
<div className="main-title">
<h2 className="text-center text-4xl text-sky-800 mb-[15px]">
Blog
</h2>
<h2 className="text-center text-4xl text-sky-800 mb-[15px]">Blog</h2>
<div className="text-center text-base text-gray-400">
Cập nhật từ Hurasoft
</div>
</div>
<Suspense>
{loadingUi ? (
<>
<div className="box-big-article flex">
<div className="box-big" id="js-holder-big">
<div className="relative">
@@ -65,7 +68,10 @@ const HomeArticle = () => {
<h2 className="title text-xl font-bold mb-[25px]">
Xem thêm bài khác
</h2>
<div className="list-article flex flex-wrap" id="js-list-article">
<div
className="list-article flex flex-wrap"
id="js-list-article"
>
<div className="item-article">
<div className="bg-gray-300 w-[full] h-[202px] block rounded-[12px]"></div>
<div className="info mt-[10px]">
@@ -110,132 +116,33 @@ const HomeArticle = () => {
</div>
</div>
</div>
</div>
</div>
</>
) : (
<div className="page-article">
<div className="container">
<div className="main-title">
<h2 className="text-center text-4xl text-sky-800 mb-[15px]">
Blog
</h2>
<div className="text-center text-base text-gray-400">
Cập nhật từ Hurasoft
</div>
</div>
<>
{articleList &&
Array.isArray(articleList) &&
articleList.length > 0 ? (
<div>
<div className="box-big-article flex">
<div className="box-big" id="js-holder-big">
{articleList.slice(0, 1).map((item) => (
<div className="item-article" key={item.id}>
<a
href={`/article${item.url}`}
className="image-article"
>
<img
src={`https://hurasoft8.hurasoft.com/${item.image.large}`}
width={100}
height={100}
alt={item.title}
/>
</a>
<div className="info">
<div className="time">
<i className="fa-regular fa-clock"></i>{" "}
<span>
{format(
new Date(item.last_update * 1000),
"dd/MM/yyyy HH:mm"
)}
</span>
</div>
<a
href={`/article${item.url}`}
className="name-article line-clamp-2"
>
{item.title}
</a>
</div>
</div>
<div className="box-big w-full">
{articleList.slice(0, 1).map((article) => (
<ArticleItem key={article.id} article={article} />
))}
</div>
<div className="box-small" id="js-holder-small">
{articleList.slice(1, 3).map((item) => (
<div className="item-article" key={item.id}>
<a
href={`/article/${item.url}`}
className="image-article"
>
<img
src={`https://hurasoft8.hurasoft.com/${item.image.large}`}
width={100}
height={100}
alt={item.title}
/>
</a>
<div className="info">
<div className="time">
<i className="fa-regular fa-clock"></i>{" "}
<span>
{format(
new Date(item.last_update * 1000),
"dd/MM/yyyy HH:mm"
)}
</span>
</div>
<a
href={`/article/${item.url}`}
className="name-article line-clamp-2"
>
{item.title}
</a>
</div>
</div>
<div className="box-small">
{articleList?.slice(1, 3).map((article) => (
<ArticleItem key={article.id} article={article} />
))}
</div>
</div>
<div className="box-article-other mt-[50px]">
<h2 className="title text-xl font-bold mb-[25px]">
Xem thêm bài khác
</h2>
<div
className="list-article flex flex-wrap"
id="js-list-article"
>
{articleList.map((item) => (
<div className="item-article" key={item.id}>
<Link
href={`/article/${item.url}`}
className="image-article"
>
<img
src={`https://hurasoft8.hurasoft.com/${item.image.large}`}
width={100}
height={100}
alt={item.title}
/>
</Link>
<div className="info">
<div className="time">
<i className="fa-regular fa-clock"></i>{" "}
<span>
{format(
new Date(item.last_update * 1000),
"dd/MM/yyyy HH:mm"
)}
</span>
</div>
<Link
href={`/article/${item.url}`}
className="name-article line-clamp-2"
>
{item.title}
</Link>
</div>
</div>
<div className="list-article flex flex-wrap">
{articleList.map((article) => (
<ArticleItem key={article.id} article={article} />
))}
</div>
</div>
@@ -243,10 +150,11 @@ const HomeArticle = () => {
) : (
<></>
)}
</div>
</div>
</>
)}
</Suspense>
</div>
</div>
);
};

View File

@@ -30,35 +30,35 @@ const JobDetails = () => {
<Suspense>
{loadingUi ? (
<div className="container-job">
<h2 className="title animate-fade-in text-xl font-medium bg-gray-200 rounded-[12px]"></h2>
<h2 className="w-full h-[100px] mb-[50px] text-xl font-medium bg-gray-300 rounded-[12px] animate-pulse"></h2>
<div className="content-job flex">
<div className="left-job">
<div className="item">
<p className="bg-gray-200 h-[20px] block w-full"></p>
<b className="bg-gray-200 h-[20px] block w-full"></b>
<p className="bg-gray-300 h-[20px] block w-full animate-pulse"></p>
<b className="bg-gray-300 h-[20px] block w-full animate-pulse"></b>
</div>
<div className="item">
<p className="bg-gray-200 h-[20px] block w-full"></p>
<b className="bg-gray-200 h-[20px] block w-full"></b>
<p className="bg-gray-300 h-[20px] block w-full animate-pulse"></p>
<b className="bg-gray-300 h-[20px] block w-full animate-pulse"></b>
</div>
<div className="item">
<p className="bg-gray-200 h-[20px] block w-full"></p>
<b className="bg-gray-200 h-[20px] block w-full"></b>
<p className="bg-gray-300 h-[20px] block w-full animate-pulse"></p>
<b className="bg-gray-300 h-[20px] block w-full animate-pulse"></b>
</div>
</div>
<div className="right-job">
<div className="list-tab flex items-center">
<div className="item-tab bg-gray-200 w-[170px] h-[45px] mr-[12px] rounded-[5px]"></div>
<div className="item-tab bg-gray-200 w-[170px] h-[45px] mr-[12px] rounded-[5px]"></div>
<div className="item-tab bg-gray-300 w-[170px] h-[45px] mr-[12px] rounded-[5px] animate-pulse"></div>
<div className="item-tab bg-gray-300 w-[170px] h-[45px] mr-[12px] rounded-[5px] animate-pulse"></div>
</div>
<div>
<div className="bg-gray-200 w-full h-[30px] rounded-[5px] ml-[20px] mb-[20px]"></div>
<div className="bg-gray-300 w-full h-[30px] rounded-[5px] ml-[20px] mb-[20px] animate-pulse"></div>
<ul>
<li className="bg-gray-200 w-full h-[20px] rounded-[5px] mb-[10px] ml-[10px]"></li>
<li className="bg-gray-200 w-full h-[20px] rounded-[5px] mb-[10px] ml-[10px]"></li>
<li className="bg-gray-200 w-full h-[20px] rounded-[5px] mb-[10px] ml-[10px]"></li>
<li className="bg-gray-200 w-full h-[20px] rounded-[5px] mb-[10px] ml-[10px]"></li>
<li className="bg-gray-200 w-full h-[20px] rounded-[5px] mb-[10px] ml-[10px]"></li>
<li className="bg-gray-300 w-full h-[20px] rounded-[5px] mb-[10px] ml-[10px] animate-pulse"></li>
<li className="bg-gray-300 w-full h-[20px] rounded-[5px] mb-[10px] ml-[10px] animate-pulse"></li>
<li className="bg-gray-300 w-full h-[20px] rounded-[5px] mb-[10px] ml-[10px] animate-pulse"></li>
<li className="bg-gray-300 w-full h-[20px] rounded-[5px] mb-[10px] ml-[10px] animate-pulse"></li>
<li className="bg-gray-300 w-full h-[20px] rounded-[5px] mb-[10px] ml-[10px] animate-pulse"></li>
</ul>
</div>
</div>

View File

@@ -1,94 +1,53 @@
"use client";
import Link from "next/link";
import { Suspense, useState, useEffect } from "react";
import { ListJobDataType } from "@/types/job";
import { useState, useEffect } from "react";
import { fetchListJobs } from "@/api/apiService";
import JobItem from "@/components/jobs/JobItem";
import { ListJobDataType } from "@/types/job";
const HomeJob = () => {
const [ListJob, setListJob] = useState<ListJobDataType | null>(null);
const [jobList, setJobList] = useState<ListJobDataType | null>(null);
const [loadingUi, setLoadingUI] = useState(true);
useEffect(() => {
const getListJob = async () => {
const getJobList = async () => {
try {
const data = await fetchListJobs();
setListJob(data.list);
setJobList(data.list);
} catch (error) {
console.error("Failed to fetch jobs:", error);
} finally {
setLoadingUI(false);
}
};
getListJob();
getJobList();
}, []);
return (
<div className="page-job list">
<div className="container-job">
<h2 className="title">Tuyển dụng</h2>
<Suspense>
{loadingUi ? (
<div className="list-job">
<div className="item-job">
{[...Array(4)].map((_, index) => (
<div className="item-job" key={index}>
<div className="job-left flex items-center">
<div className="name line-clamp-1 bg-gray-200 h-[21px] w-[300px] mr-[15px]"></div>
<div className="time bg-gray-200 h-[20px] w-[120px] block"></div>
<div className="name line-clamp-1 bg-gray-200 h-[21px] w-[300px] mr-[15px] animate-pulse"></div>
<div className="time bg-gray-200 h-[20px] w-[120px] block animate-pulse"></div>
</div>
<div className="job-right flex items-center">
<div className="localhost bg-gray-200 h-[21px] w-[60px] mr-[20px] block"></div>
<div className="more bg-gray-200 h-[21px] block w-[120px]"></div>
</div>
</div>
<div className="item-job">
<div className="job-left flex items-center">
<div className="name line-clamp-1 bg-gray-200 h-[21px] w-[300px] mr-[15px]"></div>
<div className="time bg-gray-200 h-[20px] w-[120px] block"></div>
</div>
<div className="job-right flex items-center">
<div className="localhost bg-gray-200 h-[21px] w-[60px] mr-[20px] block"></div>
<div className="more bg-gray-200 h-[21px] block w-[120px]"></div>
</div>
</div>
<div className="item-job">
<div className="job-left flex items-center">
<div className="name line-clamp-1 bg-gray-200 h-[21px] w-[300px] mr-[15px]"></div>
<div className="time bg-gray-200 h-[20px] w-[120px] block"></div>
</div>
<div className="job-right flex items-center">
<div className="localhost bg-gray-200 h-[21px] w-[60px] mr-[20px] block"></div>
<div className="more bg-gray-200 h-[21px] block w-[120px]"></div>
</div>
</div>
<div className="item-job">
<div className="job-left flex items-center">
<div className="name line-clamp-1 bg-gray-200 h-[21px] w-[300px] mr-[15px]"></div>
<div className="time bg-gray-200 h-[20px] w-[120px] block"></div>
</div>
<div className="job-right flex items-center">
<div className="localhost bg-gray-200 h-[21px] w-[60px] mr-[20px] block"></div>
<div className="more bg-gray-200 h-[21px] block w-[120px]"></div>
<div className="localhost bg-gray-200 h-[21px] w-[60px] mr-[20px] block animate-pulse"></div>
<div className="more bg-gray-200 h-[21px] block w-[120px] animate-pulse"></div>
</div>
</div>
))}
</div>
) : (
<div>
{ListJob && Array.isArray(ListJob) && ListJob.length > 0 ? (
{jobList && Array.isArray(jobList) && jobList.length > 0 ? (
<div className="list-job">
{ListJob.map((item) => (
<div className="item-job" key={item.id}>
<div className="job-left">
<Link
href={`${item.url}`}
className="name line-clamp-1"
>
{item.title}
</Link>
<div className="time">{item.end_date}</div>
</div>
<div className="job-right flex items-center">
<div className="localhost">{item.location}</div>
<Link href={`${item.url}`} className="more">
ng tuyển ngay{" "}
<i className="fa-solid fa-angle-right"></i>
</Link>
</div>
</div>
{jobList.map((job) => (
<JobItem key={job.id} job={job} />
))}
</div>
) : (
@@ -98,7 +57,6 @@ const HomeJob = () => {
)}
</div>
)}
</Suspense>
</div>
</div>
);

View File

@@ -1,44 +1,26 @@
"use client";
import { Suspense, useState, useEffect } from "react";
import Image from "next/image";
import { Suspense, useEffect } from "react";
import Link from "next/link";
import { format } from "date-fns";
import Image from "next/image";
import useArticles from "@/hooks/useArticles"; // Import custom hook
import ProductCard from "@/components/products/ProductCard";
import ArticleCard from "@/components/articles/ArticleCard";
import { homePageEffect } from "@/effects/homeEffect";
import { ArticleListDataType } from "@/types/article";
import { fetchListArticles } from "@/api/apiService";
export default function Home() {
const [articlesList, setArticleList] = useState<ArticleListDataType | null>(
null
);
const [loadingUi, setLoadingUI] = useState(true);
const { articles, loading, error } = useArticles(); // Dùng hook để lấy dữ liệu
useEffect(() => {
const typingNode = document.getElementById("typewriter") as HTMLElement;
if (typingNode) {
homePageEffect.showTypingEffect(typingNode);
const typingElement = document.getElementById("typewriter") as HTMLElement;
if (typingElement) {
homePageEffect.showTypingEffect(typingElement);
}
// slider đối tác
homePageEffect.startCarousel("#navheight", true, 3000);
const fetchArticleNews = async () => {
try {
const data = await fetchListArticles();
setArticleList(data.list);
setLoadingUI(false);
} catch (error) {
console.log("Failed to fetch articles", error);
}
};
fetchArticleNews();
}, []);
return (
<>
<div className="homepage">
{/* Slogan */}
<div className="box-slogan">
<div className="content-slogan">
<div className="main-sologan">
@@ -49,8 +31,8 @@ export default function Home() {
<span className="caret"></span>
</div>
<div className="note">
vấn phát triển website, marketing online, chăm sóc khách
hàng, tên miền, cloud hosting
vấn phát triển website, marketing online, chăm sóc khách hàng,
tên miền, cloud hosting
</div>
<div className="group-btn flex items-center justify-center">
<Link href="/contact" className="btn btn-contact">
@@ -61,6 +43,7 @@ export default function Home() {
</div>
</div>
{/* Khách hàng đồng hành */}
<div className="box-customer">
<div className="container">
<h2 className="title">Khách hàng đng hành</h2>
@@ -474,12 +457,13 @@ export default function Home() {
</div>
</div>
</div>
{/* Sản phẩm */}
<Suspense>
<div className="box-product">
<div className="container">
<h2 className="title">Sản phẩm</h2>
{loadingUi ? (
{loading ? (
<div className="list-product flex">
<div className="item-product">
<div className="top">
@@ -511,93 +495,43 @@ export default function Home() {
</div>
</div>
) : (
<div className="list-product flex">
<div className="item-product">
<div className="top">
<div className="icon">
<Image
src="/images/icon-hura8.png"
width={100}
height={100}
alt="hura 8"
<div className="product-list flex">
<ProductCard
title="Phần mềm tạo website TMĐT"
description="Phần mềm tạo website TMĐT chạy trên nền tảng Cloud dành cho doanh nghiệp lớn"
imageSrc="/images/icon-hura8.png"
link="//hura8.com"
/>
</div>
<p className="txt line-clamp-5">
Phần mềm tạo website TMĐT chạy nên nền tảng Cloud dành
cho doanh nghiệp lớn
</p>
</div>
<a href="//hura8.com" target="_blank" className="more">
Xem thêm <i className="fa-solid fa-arrow-right"></i>
</a>
</div>
<div className="item-product">
<div className="top">
<div className="icon">
<Image
src="/images/logo-xstore.png"
width={93}
height={35}
alt="xstore"
<ProductCard
title="Nền tảng quản lý cửa hàng nhỏ"
description="Nền tảng quản lý cửa hàng nhỏ toàn diện, bao gồm quản lý đơn hàng đa kênh, kho hàng, website và POS"
imageSrc="/images/logo-xstore.png"
link="//xstore.vn"
/>
</div>
<p className="txt line-clamp-5">
Nền tảng quản cửa hàng nhỏ toàn diện, bao gồm: Quản
đơn hàng đa kênh, Kho hàng, Website POS
</p>
</div>
<a href="//xstore.vn" target="_blank" className="more">
Xem thêm <i className="fa-solid fa-arrow-right"></i>
</a>
</div>
<div className="item-product">
<div className="top">
<div className="icon">
<Image
src="/images/icon-adman.png"
width={100}
height={100}
alt="icon-adman"
<ProductCard
title="Nền tảng marketing toàn diện"
description="Nền tảng marketing toàn diện dành cho các chuyên gia."
imageSrc="/images/icon-adman.png"
link="//adman.vn"
/>
</div>
<p className="txt line-clamp-5">
Nền tảng marketing toàn diện dành cho các chuyên gia.
</p>
</div>
<a href="//adman.vn" target="_blank" className="more">
Xem thêm <i className="fa-solid fa-arrow-right"></i>
</a>
</div>
<div className="item-product chatngay">
<div className="top">
<div className="icon">
<Image
src="/images/icon-chatngay.png"
width={100}
height={100}
alt="icon-chatngay"
<ProductCard
title="Phần mềm hỗ trợ CSKH"
description="Phần mềm hỗ trợ, CSKH tích hợp website giúp khách hàng tương tác nhanh chóng và thuận tiện."
imageSrc="/images/icon-chatngay.png"
link="//chatngay.com"
/>
</div>
<p className="txt line-clamp-5">
Phần mềm hỗ trợ, cskh tích hợp website giúp khách hàng
tương tác nhanh chóng thuận tiện.
</p>
</div>
<a href="//chatngay.com" target="_blank" className="more">
Xem thêm <i className="fa-solid fa-arrow-right"></i>
</a>
</div>
</div>
)}
</div>
</div>
</Suspense>
{/* Bài viết mới */}
<Suspense>
<div className="box-article">
<section className="box-article">
<div className="container">
<h2 className="title"> mới?</h2>
{loadingUi ? (
{loading || error ? (
<div className="content-item-article" id="js-article-new">
<div className="flex">
<div className="info">
@@ -610,59 +544,18 @@ export default function Home() {
<div className="image-right bg-gray-100 h-[370px] rounded-[12px]"></div>
</div>
</div>
) : Array.isArray(articlesList) && articlesList.length > 0 ? (
<div className="content-item-article" id="js-article-new">
{articlesList.slice(0, 1).map((item) => (
<div className="flex" key={item.id}>
<div className="info">
<div className="tag-blog flex items-center">
<i className="icon_2024 blog"></i>
<span>Blog</span>
</div>
<a href={item.url} className="name line-clamp-4">
{item.title}
</a>
<div className="summary line-clamp-4">
{item.summary}
</div>
<a href={item.url} className="more">
Chi tiết <i className="fa-solid fa-arrow-right"></i>
</a>
<div className="info-author">
<div className="author flex items-center">
<span>Đăng bởi</span>
<span className="name-author">Admin</span>
</div>
<div className="time">
<i className="far fa-clock"></i>{" "}
<span>
{format(
new Date(item.last_update * 1000),
"dd/MM/yyyy HH:mm"
)}
</span>
</div>
</div>
</div>
<div className="image-right">
<img
src={`https://hurasoft8.hurasoft.com/${item.image.large}`}
width={100}
height={100}
alt={item.title}
/>
</div>
</div>
) : Array.isArray(articles) && articles.length > 0 ? (
<div className="content-item-article">
{articles.slice(0, 1).map((article) => (
<ArticleCard key={article.id} article={article} />
))}
</div>
) : (
<></> // Nếu không có dữ liệu, không hiển thị gì
<div>Không bài viết nào.</div>
)}
</div>
</div>
</section>
</Suspense>
</div>
</>
);
}

View File

@@ -1,7 +0,0 @@
export default function LoadingUI({ width = "100%", height = "150px" }) {
return (
<div style={{ width, height }} className="loading-box">
<div className="loading-content">Đang tải...</div>
</div>
);
}

View File

@@ -0,0 +1,44 @@
// ArticleCard.tsx
import { format } from "date-fns";
import { Article } from "@/types/article";
const ArticleCard = ({ article }: { article: Article }) => (
<div className="flex" key={article.id}>
<div className="info">
<div className="tag-blog flex items-center">
<i className="icon_2024 blog"></i>
<span>Blog</span>
</div>
<a href={article.url} className="name line-clamp-4">
{article.title}
</a>
<div className="summary line-clamp-4">{article.summary}</div>
<a href={article.url} className="more">
Chi tiết <i className="fa-solid fa-arrow-right"></i>
</a>
<div className="info-author">
<div className="author flex items-center">
<span>Đăng bởi</span>
<span className="name-author">Admin</span>
</div>
<div className="time">
<i className="far fa-clock"></i>{" "}
<span>
{format(new Date(article.last_update * 1000), "dd/MM/yyyy HH:mm")}
</span>
</div>
</div>
</div>
<div className="image-right">
<img
src={`https://hurasoft8.hurasoft.com/${article.image.large}`}
width={100}
height={100}
alt={article.title}
/>
</div>
</div>
);
export default ArticleCard;

View File

@@ -0,0 +1,28 @@
import { format } from "date-fns";
import { Article } from "@/types/article";
const ArticleItem = ({ article }: { article: Article }) => (
<div className="item-article">
<a href={`/article/${article.url}`} className="image-article">
<img
src={`https://hurasoft8.hurasoft.com/${article.image.large}`}
width={100}
height={100}
alt={article.title}
/>
</a>
<div className="info">
<div className="time">
<i className="fa-regular fa-clock"></i>{" "}
<span>
{format(new Date(article.last_update * 1000), "dd/MM/yyyy HH:mm")}
</span>
</div>
<a href={`/article/${article.url}`} className="name-article line-clamp-2">
{article.title}
</a>
</div>
</div>
);
export default ArticleItem;

View File

@@ -0,0 +1,21 @@
import Link from "next/link";
import { JobdataType } from "@/types/job";
const JobItem = ({ job }: { job: JobdataType }) => (
<div className="item-job" key={job.id}>
<div className="job-left">
<Link href={job.url} className="name line-clamp-1">
{job.title}
</Link>
<div className="time">{job.end_date}</div>
</div>
<div className="job-right flex items-center">
<div className="localhost">{job.location}</div>
<Link href={job.url} className="more">
ng tuyển ngay <i className="fa-solid fa-angle-right"></i>
</Link>
</div>
</div>
);
export default JobItem;

View File

@@ -0,0 +1,27 @@
import Image from "next/image";
const ProductCard = ({
title,
description,
imageSrc,
link,
}: {
title: string;
description: string;
imageSrc: string;
link: string;
}) => (
<div className="item-product">
<div className="top">
<div className="icon">
<Image src={imageSrc} width={100} height={100} alt={title} />
</div>
<p className="txt line-clamp-5">{description}</p>
</div>
<a href={link} target="_blank" className="more">
Xem thêm <i className="fa-solid fa-arrow-right"></i>
</a>
</div>
);
export default ProductCard;

29
src/hooks/useArticles.ts Normal file
View File

@@ -0,0 +1,29 @@
import { useState, useEffect } from "react";
import { ArticleListDataType } from "@/types/article";
import { fetchListArticles } from "@/api/apiService";
// Custom Hook để lấy danh sách bài viết
const useArticles = () => {
const [articles, setArticles] = useState<ArticleListDataType | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchArticles = async () => {
try {
const data = await fetchListArticles();
setArticles(data.list);
} catch {
setError('Lỗi khi tải bài viết.');
} finally {
setLoading(false);
}
};
fetchArticles();
}, []);
return { articles, loading, error };
};
export default useArticles;