mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 17:38:12 +00:00
292 lines
11 KiB
TypeScript
292 lines
11 KiB
TypeScript
import { useLocalizedName } from "@/shared/common/localizedName";
|
|
import { useGoal } from "@/user-management/web-Management/hooks/useGoal";
|
|
import { useTheme } from "@/user-management/web-Management/hooks/useTheme";
|
|
import { useVision } from "@/user-management/web-Management/hooks/useVision";
|
|
import React, { useState, useEffect } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
const OrganizationGoals = () => {
|
|
const [currentGoalIndex, setCurrentGoalIndex] = useState(0);
|
|
const [isMobile, setIsMobile] = useState(false);
|
|
const localizedName = useLocalizedName();
|
|
const { t } = useTranslation();
|
|
|
|
const baseParams = {
|
|
isActive: true,
|
|
};
|
|
const { items } = useGoal(baseParams);
|
|
const { items: theme, unit } = useTheme();
|
|
const { items: vision } = useVision(baseParams);
|
|
const goals: any[] = items ?? [];
|
|
|
|
// Auto-rotate goals
|
|
useEffect(() => {
|
|
if (items?.length) {
|
|
const interval = setInterval(() => {
|
|
setCurrentGoalIndex((prevIndex) =>
|
|
prevIndex === goals?.length - 1 ? 0 : prevIndex + 1
|
|
);
|
|
}, 3000);
|
|
return () => clearInterval(interval);
|
|
}
|
|
}, [goals?.length, items]);
|
|
|
|
// Responsive
|
|
useEffect(() => {
|
|
const checkScreenSize = () => {
|
|
setIsMobile(window.innerWidth < 768);
|
|
};
|
|
checkScreenSize();
|
|
window.addEventListener("resize", checkScreenSize);
|
|
return () => window.removeEventListener("resize", checkScreenSize);
|
|
}, []);
|
|
|
|
const goToGoal = (index: any) => {
|
|
setCurrentGoalIndex(index);
|
|
};
|
|
|
|
const currentGoal = goals[currentGoalIndex];
|
|
|
|
function lightenColor(color: string, percent: number) {
|
|
const R = parseInt(color.substring(1, 3), 16);
|
|
const G = parseInt(color.substring(3, 5), 16);
|
|
const B = parseInt(color.substring(5, 7), 16);
|
|
const newR = Math.min(255, R + Math.round((255 - R) * (percent / 100)));
|
|
const newG = Math.min(255, G + Math.round((255 - G) * (percent / 100)));
|
|
const newB = Math.min(255, B + Math.round((255 - B) * (percent / 100)));
|
|
return `#${newR.toString(16).padStart(2, "0")}${newG
|
|
.toString(16)
|
|
.padStart(2, "0")}${newB.toString(16).padStart(2, "0")}`;
|
|
}
|
|
|
|
return (
|
|
<div
|
|
className="min-h-screen flex items-center justify-center p-4 md:p-8"
|
|
style={{
|
|
background: `linear-gradient(
|
|
to bottom,
|
|
${
|
|
theme?.find((i) => i.type === "PRIMARY_COLOR")?.value
|
|
? lightenColor(
|
|
theme.find((i) => i.type === "PRIMARY_COLOR")!.value,
|
|
30
|
|
)
|
|
: "var(--primary-300)"
|
|
},
|
|
${
|
|
theme?.find((i) => i.type === "SECONDARY_COLOR")?.value
|
|
? lightenColor(
|
|
theme.find((i) => i.type === "SECONDARY_COLOR")!.value,
|
|
55
|
|
)
|
|
: "var(--primary-300)"
|
|
}
|
|
)`,
|
|
}}>
|
|
<div className="max-w-6xl w-full">
|
|
{/* Header */}
|
|
<div className="text-center mb-12">
|
|
<div className="flex flex-col md:flex-row items-center justify-center mb-6">
|
|
{/* Logo */}
|
|
<div
|
|
className="overflow-hidden flex items-center justify-center shadow-lg mb-4 md:mb-0 md:mr-6"
|
|
style={{
|
|
width: "150px",
|
|
height: "150px",
|
|
borderRadius: "16px", // change to "50%" for full circle
|
|
flexShrink: 0,
|
|
}}>
|
|
<img
|
|
src={
|
|
theme?.find((i) => i.type === "LOGO")?.presigned ||
|
|
"https://www.w3.org/Icons/w3c_home"
|
|
}
|
|
alt={localizedName(unit?.name)}
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
</div>
|
|
|
|
{/* Text */}
|
|
<div className="max-w-xs md:max-w-md break-words text-center md:text-left">
|
|
<h2 className="text-3xl md:text-4xl font-bold text-gray-800 mb-2 leading-tight">
|
|
{localizedName(unit?.name)}
|
|
</h2>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Decorative line */}
|
|
<div
|
|
className="w-32 h-1 mx-auto rounded-full"
|
|
style={{
|
|
background: `linear-gradient(to right, ${
|
|
theme?.find((i) => i.type === "PRIMARY_COLOR")?.value ||
|
|
"#3b82f6"
|
|
}, ${
|
|
theme?.find((i) => i.type === "SECONDARY_COLOR")?.value ||
|
|
"#9333ea"
|
|
})`,
|
|
}}></div>
|
|
</div>
|
|
|
|
{/* Goals */}
|
|
<div className="bg-white rounded-2xl shadow-xl overflow-hidden transition-all duration-300 min-h-[470px] hover:shadow-2xl mb-12">
|
|
<div className="flex flex-col md:flex-row">
|
|
<div className="md:w-2/3 p-6 md:p-8 flex flex-col justify-center">
|
|
<div className="mb-6">
|
|
<div className="flex items-center mb-6">
|
|
<div
|
|
className="w-12 h-12 rounded-lg flex items-center justify-center mr-4 overflow-hidden"
|
|
style={{
|
|
background: `linear-gradient(to right, ${
|
|
theme?.find((i) => i.type === "SECONDARY_COLOR")
|
|
?.value || "#32CD32"
|
|
}, ${
|
|
theme?.find((i) => i.type === "SECONDARY_COLOR")
|
|
?.value || "#FFFFFF"
|
|
})`,
|
|
}}>
|
|
<img
|
|
src={
|
|
currentGoal?.presigned ||
|
|
"https://www.w3.org/Icons/w3c_home"
|
|
}
|
|
alt="Goal Icon"
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<h3 className="text-lg font-semibold text-gray-600 uppercase tracking-wide">
|
|
{t("Strategic Goal")} {currentGoalIndex + 1} {t("of")}{" "}
|
|
{goals?.length}
|
|
</h3>
|
|
<h2 className="text-2xl md:text-3xl font-bold text-gray-800 mt-1">
|
|
{localizedName(currentGoal?.goalTitle)}
|
|
</h2>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="min-h-[120px] flex items-center">
|
|
<p className="text-gray-700 text-lg leading-relaxed transition-opacity duration-500">
|
|
{localizedName(currentGoal?.goalDescription) ||
|
|
t("msg.waitingMsg")}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-6">
|
|
<div className="flex justify-between items-center mb-4">
|
|
<span className="text-gray-600 text-sm">
|
|
{t("Our Strategic Goals")}
|
|
</span>
|
|
</div>
|
|
|
|
<div className="flex space-x-2 mb-4">
|
|
{goals?.map((_, index) => (
|
|
<button
|
|
key={index}
|
|
onClick={() => goToGoal(index)}
|
|
className={`flex-1 h-2 rounded-full transition-all duration-300 ${
|
|
index !== currentGoalIndex
|
|
? "bg-gray-200 hover:bg-gray-300"
|
|
: ""
|
|
}`}
|
|
style={
|
|
index === currentGoalIndex
|
|
? {
|
|
background: `linear-gradient(to right, ${
|
|
theme?.find((i) => i.type === "PRIMARY_COLOR")
|
|
?.value || "#00FF00"
|
|
})`,
|
|
}
|
|
: {}
|
|
}
|
|
aria-label={t("Go to goal", {
|
|
index: index + 1,
|
|
title: localizedName(goals[index].goalTitle),
|
|
})}
|
|
/>
|
|
))}
|
|
</div>
|
|
|
|
<div className="flex justify-between">
|
|
<button
|
|
onClick={() =>
|
|
goToGoal(
|
|
currentGoalIndex === 0
|
|
? goals?.length - 1
|
|
: currentGoalIndex - 1
|
|
)
|
|
}
|
|
className="flex items-center text-gray-600 hover:text-gray-800 transition-colors">
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
className="h-5 w-5 mr-1"
|
|
viewBox="0 0 20 20"
|
|
fill="currentColor">
|
|
<path
|
|
fillRule="evenodd"
|
|
d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z"
|
|
clipRule="evenodd"
|
|
/>
|
|
</svg>
|
|
{t("Previous Goal")}
|
|
</button>
|
|
|
|
<button
|
|
onClick={() =>
|
|
goToGoal(
|
|
currentGoalIndex === goals?.length - 1
|
|
? 0
|
|
: currentGoalIndex + 1
|
|
)
|
|
}
|
|
className="flex items-center text-gray-600 hover:text-gray-800 transition-colors">
|
|
{t("Next Goal")}
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
className="h-5 w-5 ml-1"
|
|
viewBox="0 0 20 20"
|
|
fill="currentColor">
|
|
<path
|
|
fillRule="evenodd"
|
|
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
|
|
clipRule="evenodd"
|
|
/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Vision Section */}
|
|
<div className="md:w-1/3 bg-gradient-to-br from-blue-50 to-indigo-100 p-6 md:p-8 flex flex-col justify-center items-center">
|
|
<div className="text-center">
|
|
<div className="w-32 h-32 mx-auto mb-6 bg-white rounded-2xl shadow-lg overflow-hidden">
|
|
<img
|
|
src={
|
|
currentGoal?.presigned ||
|
|
"https://www.w3.org/Icons/w3c_home"
|
|
}
|
|
alt="Vision Image"
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
</div>
|
|
|
|
<h3 className="text-xl font-bold text-gray-800 mb-2">
|
|
{localizedName(vision?.[0]?.visionTitle)}
|
|
</h3>
|
|
<p className="text-gray-600">
|
|
{localizedName(vision?.[0]?.visionDescription)}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default OrganizationGoals;
|