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": [
{

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,32 +9,132 @@ 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 (
<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>
{articleList && Array.isArray(articleList) && articleList.length > 0 ? (
<div className="box-big-article flex">
<div className="box-big" id="js-holder-big">
<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">
<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]">
<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="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 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">
<a
href={`/article${item.url}`}
className="image-article"
>
<img
src={`https://hurasoft8.hurasoft.com/${item.image.large}`}
width={100}
@@ -65,7 +165,10 @@ const HomeArticle = () => {
<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">
<a
href={`/article/${item.url}`}
className="image-article"
>
<img
src={`https://hurasoft8.hurasoft.com/${item.image.large}`}
width={100}
@@ -98,7 +201,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"
>
{articleList.map((item) => (
<div className="item-article" key={item.id}>
<Link
@@ -139,6 +245,8 @@ const HomeArticle = () => {
)}
</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,10 +470,43 @@ export default function Home() {
</div>
</div>
</div>
<Suspense>
<div className="box-product">
<div className="container">
<h2 className="title">Sản phẩm</h2>
{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>
<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>
<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>
<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>
</div>
) : (
<div className="list-product flex">
<div className="item-product">
<div className="top">
@@ -483,8 +519,8 @@ export default function Home() {
/>
</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
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">
@@ -502,8 +538,8 @@ export default function Home() {
/>
</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
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">
@@ -539,8 +575,8 @@ export default function Home() {
/>
</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.
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">
@@ -548,13 +584,29 @@ export default function Home() {
</a>
</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>
{loadingUi ? (
<div className="content-item-article" id="js-article-new">
<div className="flex">
<div className="info">
<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>
) : 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}>
@@ -566,7 +618,9 @@ export default function Home() {
<a href={item.url} className="name line-clamp-4">
{item.title}
</a>
<div className="summary line-clamp-4">{item.summary}</div>
<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>
@@ -598,12 +652,13 @@ export default function Home() {
</div>
))}
</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%;