214 lines
6.5 KiB
TypeScript
214 lines
6.5 KiB
TypeScript
//این فایل مخصوص
|
||
//شماتیک بندر امام
|
||
import React from "react";
|
||
import { formatNumber } from "~/lib/utils";
|
||
|
||
export type CompanyInfo = {
|
||
id: string;
|
||
imageUrl: string;
|
||
name: string;
|
||
costReduction: number;
|
||
revenue?: number;
|
||
capacity?: number;
|
||
costI : number,
|
||
capacityI : number,
|
||
revenueI : number,
|
||
cost : number | string,
|
||
};
|
||
|
||
export type D3ImageInfoProps = {
|
||
companies: CompanyInfo[];
|
||
width?: number;
|
||
height?: number;
|
||
};
|
||
|
||
const InfoBox = ({ company, style }: { company: CompanyInfo; style :any }) => {
|
||
const hideCapacity = company.name === "خوارزمی"; // اگر خوارزمی بود ظرفیت مخفی شود
|
||
return (
|
||
<div className={`info-box`} style={style}>
|
||
<div className="info-box-content">
|
||
<div className="info-row">
|
||
<div className="info-label">درآمد:</div>
|
||
<div className="info-value revenue text-[12px]">{formatNumber(company?.revenue || 0)}</div>
|
||
<div className="info-unit">میلیون ریال</div>
|
||
</div>
|
||
<div className="info-row">
|
||
<div className="info-label">هزینه:</div>
|
||
{
|
||
(hideCapacity ?
|
||
|
||
<div className="info-value cost2 text-[12px]">{formatNumber(company?.cost || 0)}</div>
|
||
:
|
||
<div className="info-value cost text-[12px]">{formatNumber(company?.cost || 0)}</div>
|
||
)
|
||
|
||
}
|
||
<div className="info-unit">میلیون ریال</div>
|
||
</div>
|
||
{!hideCapacity && (
|
||
<div className="info-row">
|
||
<div className="info-label">ظرفیت:</div>
|
||
<div className="info-value capacity text-[12px]">{formatNumber(company?.capacity || 0)}</div>
|
||
<div className="info-unit">تن در سال</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export function D3ImageInfo({ companies }: D3ImageInfoProps) {
|
||
// Ensure we have exactly 6 companies
|
||
|
||
const sample = [
|
||
{ id: "آب نیرو", name: "آب نیرو", imageUrl: "/abniro.png" },
|
||
{ id: "بسپاران", name: "بسپاران", imageUrl: "/besparan.png" },
|
||
{ id: "خوارزمی", name: "خوارزمی", imageUrl: "/khwarazmi.png" },
|
||
{ id: "فراورش 1", name: "فراورش 1", imageUrl: "/faravash1.png" },
|
||
{ id: "فراورش 2", name: "فراورش 2", imageUrl: "/faravash2.png" },
|
||
{ id: "کیمیا", name: "کیمیا", imageUrl: "/kimia.png" }
|
||
];
|
||
const merged = sample.map(company => {
|
||
const found = companies.find(item => item.id == company.id);
|
||
return found
|
||
? found
|
||
: { ...company, cost: 0, capacity: 0, revenue: 0 };
|
||
});
|
||
|
||
const displayCompanies = merged;
|
||
console.log(displayCompanies)
|
||
|
||
// Positions inside a 5x4 grid (col, row)
|
||
// Layout keeps same visual logic: left/middle/right on two bands with spacing grid around
|
||
const gridPositions = [
|
||
{ col: 2, row: 2 , colI : 1 , rowI : 2 , name : "بسپاران"}, // left - top band
|
||
{ col: 3, row: 2 , colI : 3 , rowI : 1 , name : "خوارزمی"}, // middle top (image sits in row 2, info box goes to row 1)
|
||
{ col: 4, row: 2 ,colI : 5 , rowI : 2 , name : "فراورش 1"}, // right - top band
|
||
{ col: 2, row: 3 , colI : 1 , rowI : 3 , name : "کیمیا"}, // left - bottom band
|
||
{ col: 3, row: 3 , colI : 3, rowI : 4 , name : "آب نیرو"}, // middle bottom (image sits in row 3, info box goes to row 4)
|
||
{ col: 4, row: 3 , colI : 5 , rowI : 3 , name : "فراورش 2"}, // right - bottom band
|
||
];
|
||
|
||
return (
|
||
<div className="w-full h-[500px] rounded-xl">
|
||
<div dir="ltr" className="company-grid-container">
|
||
{displayCompanies.map((company, index) => {
|
||
const gp = gridPositions.find(v => v.name === company.name) ;
|
||
return (
|
||
<>
|
||
<div
|
||
key={company.id}
|
||
className={`company-item`}
|
||
style={{ gridColumn: gp.col, gridRow: gp.row }}
|
||
>
|
||
<div className="company-image-containe">
|
||
<img
|
||
src={company.imageUrl}
|
||
alt={company.name}
|
||
className="company-image"
|
||
/>
|
||
</div>
|
||
|
||
{company.name}
|
||
</div>
|
||
<InfoBox company={company} key={index +10} style={{ gridColumn: gp?.colI , gridRow: gp?.rowI }} />
|
||
</>);
|
||
})}
|
||
</div>
|
||
|
||
<style jsx>{`
|
||
.company-grid-container {
|
||
display: grid;
|
||
grid-template-columns: repeat(5, 1fr);
|
||
grid-template-rows: repeat(4, 1fr);
|
||
gap: 5px;
|
||
width: 100%;
|
||
height: 500px;
|
||
}
|
||
|
||
.company-item {
|
||
border-radius: 8px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.company-image-container {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.company-image {
|
||
object-fit: contain;
|
||
height : 100px;
|
||
}
|
||
|
||
.info-box {
|
||
border: 1px solid #3F415A;
|
||
border-radius: 10px;
|
||
height: max-content;
|
||
align-self : center;
|
||
justify-self : center;
|
||
padding : .2rem 1.2rem;
|
||
min-width : 8rem;
|
||
background-color: transparent;
|
||
}
|
||
|
||
|
||
.info-box-content {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
}
|
||
|
||
.info-row {
|
||
position : relative;
|
||
margin: .1rem 0;
|
||
display: flex;
|
||
gap : .5rem;
|
||
justify-content : space-between;
|
||
direction: rtl;
|
||
|
||
&:has(.info-value.revenue) {border-bottom: 1px solid #3AEA83;}
|
||
&:has(.info-value.cost) {border-bottom: 1px solid #F76276;}
|
||
|
||
}
|
||
|
||
.info-label {
|
||
color: #FFFFFF;
|
||
font-size: 11px;
|
||
font-weight: 300;
|
||
text-align: right;
|
||
margin : auto 0;
|
||
}
|
||
|
||
.info-value {
|
||
color: #34D399;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
text-align: right;
|
||
margin-bottom : .5rem;
|
||
}
|
||
|
||
.info-value.revenue { color: #fff;}
|
||
.info-value.cost { color: #fff; }
|
||
.info-value.cost2 { color: #fff; }
|
||
.info-value.capacity { color: #fff; }
|
||
|
||
.info-unit {
|
||
position: absolute;
|
||
left: 0;
|
||
bottom: 2px;
|
||
color: #ACACAC;
|
||
font-size: 6px;
|
||
font-weight: 400;
|
||
}
|
||
`}</style>
|
||
</div>
|
||
);
|
||
}
|