update 24/03

This commit is contained in:
2025-03-24 16:00:41 +07:00
parent ef212024fd
commit b5019b41b4
6 changed files with 422 additions and 229 deletions

View File

@@ -1,5 +1,5 @@
{
"jobs": {
"list_job": {
"total": 4,
"list": [
{
@@ -76,7 +76,7 @@
}
]
},
"articles": {
"list_article": {
"total": 11,
"list": [
{
@@ -423,4 +423,4 @@
"note": "liên hệ tôi"
}
]
}
}

View File

@@ -16,13 +16,13 @@ const apiRequest = async (endpoint: string, method: string = "GET", body?: objec
return response.json();
};
// API cho bài viết
export const fetchListArticles = () => apiRequest("/articles");
export const fetchListArticles = () => apiRequest("/list_article");
export const fetchArticleDetail = async (slug: string): Promise<ArticleDetailDataType> => {
return apiRequest(`/articleDetails?path=${slug}`);
};
// API cho công việc
export const fetchListJobs = () => apiRequest("/jobs");
export const fetchListJobs = () => apiRequest("/list_job");
export const fetchJobDetail = async (slug: string): Promise<JobDetailDataType> => {
return apiRequest(`/jobDetails?path=${slug}`);
};

View File

@@ -1,5 +1,5 @@
"use client";
import { useEffect, useState } from "react";
import { Suspense, useEffect, useState } from "react";
import { format } from "date-fns";
import Link from "next/link";
import { ArticleListDataType } from "@/types/article";
@@ -9,89 +9,56 @@ const HomeArticle = () => {
const [articleList, setArticleList] = useState<ArticleListDataType | null>(
null
);
const [loadingUi, setLoadingUI] = useState(true);
useEffect(() => {
const fetchArticleList = async () => {
const data = await fetchListArticles();
setArticleList(data.list);
setLoadingUI(false);
};
fetchArticleList();
}, []);
return (
<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>
<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>
<div className="text-center text-base text-gray-400">
Cập nhật từ Hurasoft
</div>
</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 className="relative">
<div className="bg-gray-300 w-full h-[606px] block rounded-[12px]"></div>
<div className="absolute bottom-[20px] left-[20px] right-0 p-[20px] bg-gray-50 rounded-[12px] w-[90%]">
<div className="time block bg-gray-200 w-[150px] h-[30px] rounded-[6px]"></div>
<div className="block bg-gray-200 w-full h-[50px] rounded-[6px]"></div>
</div>
))}
</div>
</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 className="item]">
<div className="bg-gray-300 w-[full] h-[202px] block rounded-[12px]"></div>
<div className="info mt-[10px]">
<div className="bg-gray-300 block w-[150px] h-[20px] mb-[5px]"></div>
<div className="bg-gray-300 block w-[full] h-[48px]"></div>
</div>
))}
</div>
<div className="item]">
<div className="bg-gray-300 w-[full] h-[202px] block rounded-[12px]"></div>
<div className="info mt-[10px]">
<div className="bg-gray-300 block w-[150px] h-[20px] mb-[5px]"></div>
<div className="bg-gray-300 block w-[full] h-[48px]"></div>
</div>
</div>
</div>
</div>
<div className="box-article-other mt-[50px]">
@@ -99,46 +66,187 @@ const HomeArticle = () => {
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 className="item-article">
<div className="bg-gray-300 w-[full] h-[202px] block rounded-[12px]"></div>
<div className="info mt-[10px]">
<div className="bg-gray-300 block w-[150px] h-[20px] mb-[5px]"></div>
<div className="bg-gray-300 block w-[full] h-[48px]"></div>
</div>
))}
</div>
<div className="item-article">
<div className="bg-gray-300 w-[full] h-[202px] block rounded-[12px]"></div>
<div className="info mt-[10px]">
<div className="bg-gray-300 block w-[150px] h-[20px] mb-[5px]"></div>
<div className="bg-gray-300 block w-[full] h-[48px]"></div>
</div>
</div>
<div className="item-article">
<div className="bg-gray-300 w-[full] h-[202px] block rounded-[12px]"></div>
<div className="info mt-[10px]">
<div className="bg-gray-300 block w-[150px] h-[20px] mb-[5px]"></div>
<div className="bg-gray-300 block w-[full] h-[48px]"></div>
</div>
</div>
<div className="item-article">
<div className="bg-gray-300 w-[full] h-[202px] block rounded-[12px]"></div>
<div className="info mt-[10px]">
<div className="bg-gray-300 block w-[150px] h-[20px] mb-[5px]"></div>
<div className="bg-gray-300 block w-[full] h-[48px]"></div>
</div>
</div>
<div className="item-article">
<div className="bg-gray-300 w-[full] h-[202px] block rounded-[12px]"></div>
<div className="info mt-[10px]">
<div className="bg-gray-300 block w-[150px] h-[20px] mb-[5px]"></div>
<div className="bg-gray-300 block w-[full] h-[48px]"></div>
</div>
</div>
<div className="item-article">
<div className="bg-gray-300 w-[full] h-[202px] block rounded-[12px]"></div>
<div className="info mt-[10px]">
<div className="bg-gray-300 block w-[150px] h-[20px] mb-[5px]"></div>
<div className="bg-gray-300 block w-[full] h-[48px]"></div>
</div>
</div>
</div>
</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>
<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>
</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>
</div>
</div>
) : (
<></>
)}
</div>
</div>
)}
</Suspense>
);
};

View File

@@ -1,5 +1,5 @@
"use client";
import { useState, useEffect } from "react";
import { Suspense, useState, useEffect } from "react";
import Image from "next/image";
import Link from "next/link";
import { format } from "date-fns";
@@ -12,6 +12,8 @@ export default function Home() {
null
);
const [loadingUi, setLoadingUI] = useState(true);
useEffect(() => {
const typingNode = document.getElementById("typewriter") as HTMLElement;
if (typingNode) {
@@ -24,6 +26,7 @@ export default function Home() {
const fetchArticleNews = async () => {
const data = await fetchListArticles();
setArticleList(data.list);
setLoadingUI(false);
};
fetchArticleNews();
@@ -467,142 +470,194 @@ export default function Home() {
</div>
</div>
</div>
<Suspense>
<div className="box-product">
<div className="container">
<h2 className="title">Sản phẩm</h2>
<div className="box-product">
<div className="container">
<h2 className="title">Sản phẩm</h2>
<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"
/>
{loadingUi ? (
<div className="list-product flex">
<div className="item-product">
<div className="top">
<div className="icon w-full bg-gray-50 h-[35px] rounded-[12px]"></div>
<div className="w-full h-[100px] mb-[28px] mt-[20px] bg-gray-50 rounded-[12px]"></div>
</div>
<div className="w-full h-[16px] bg-gray-50 rounded-[12px]"></div>
</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"
/>
<div className="item-product">
<div className="top">
<div className="icon w-full bg-gray-50 h-[35px] rounded-[12px]"></div>
<div className="w-full h-[100px] mb-[28px] mt-[20px] bg-gray-50 rounded-[12px]"></div>
</div>
<div className="w-full h-[16px] bg-gray-50 rounded-[12px]"></div>
</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"
/>
<div className="item-product">
<div className="top">
<div className="icon w-full bg-gray-50 h-[35px] rounded-[12px]"></div>
<div className="w-full h-[100px] mb-[28px] mt-[20px] bg-gray-50 rounded-[12px]"></div>
</div>
<div className="w-full h-[16px] bg-gray-50 rounded-[12px]"></div>
</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"
/>
<div className="item-product">
<div className="top">
<div className="icon w-full bg-gray-50 h-[35px] rounded-[12px]"></div>
<div className="w-full h-[100px] mb-[28px] mt-[20px] bg-gray-50 rounded-[12px]"></div>
</div>
<div className="w-full h-[16px] bg-gray-50 rounded-[12px]"></div>
</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 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>
<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"
/>
</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"
/>
</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"
/>
</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>
</div>
{articleList && Array.isArray(articleList) && articleList.length > 0 ? (
</Suspense>
<Suspense>
<div className="box-article">
<div className="container">
<h2 className="title"> mới?</h2>
<div className="content-item-article" id="js-article-new">
{articleList.slice(0, 1).map((item) => (
<div className="flex" key={item.id}>
{loadingUi ? (
<div className="content-item-article" id="js-article-new">
<div className="flex">
<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 className="tag-blog block bg-gray-100 rounded-[12px] w-[74px] h-[28px]"></div>
<div className="name w-full bg-gray-100 h-[36px] rounded-[12px] mb-[24px]"></div>
<div className="summary bg-gray-100 block line-clamp-4 w-full h-[80px] rounded-[12px] mb-[20px]"></div>
<div className="more w-full h-[24px] bg-gray-100 block"></div>
<div className="info-author w-[200px] h-[50px] block bg-gray-100"></div>
</div>
<div className="image-right bg-gray-100 h-[370px] rounded-[12px]"></div>
</div>
))}
</div>
</div>
) : Array.isArray(articleList) && articleList.length > 0 ? (
<div className="content-item-article" id="js-article-new">
{articleList.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>
))}
</div>
) : (
<></> // Nếu không có dữ liệu, không hiển thị gì
)}
</div>
</div>
) : (
<></>
)}
</Suspense>
</div>
</>
);

View File

@@ -0,0 +1,7 @@
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

@@ -1137,6 +1137,29 @@ main {
width: 50%;
}
.loading-box {
background-color: #f0f0f0;
border-radius: 8px;
animation: shimmer 1.5s infinite linear;
display: flex;
justify-content: center;
align-items: center;
}
.loading-content {
font-size: 18px;
font-weight: bold;
}
@keyframes shimmer {
0% {
background-position: -1000px 0;
}
100% {
background-position: 1000px 0;
}
}
@media only screen and (max-width: 768px) {
.page-job .container-job {
width: 100%;