Compare commits
4 Commits
b07de2b03c
...
5f0fa91075
| Author | SHA1 | Date | |
|---|---|---|---|
| 5f0fa91075 | |||
| 6f1547dde7 | |||
| 234f86d6b9 | |||
| 2979634033 |
@@ -71,7 +71,7 @@ export default function FormField({
|
|||||||
|
|
||||||
// 2. Relation Handling (Select / Multi-Select)
|
// 2. Relation Handling (Select / Multi-Select)
|
||||||
if (field.relation && relationDataMap[field.relation]) {
|
if (field.relation && relationDataMap[field.relation]) {
|
||||||
const relationData = relationDataMap[field.relation];
|
const relationData = relationDataMap[field.relation].data;
|
||||||
const isArrayRelation = field.type === 'array';
|
const isArrayRelation = field.type === 'array';
|
||||||
|
|
||||||
// Determine how to display the related item
|
// Determine how to display the related item
|
||||||
|
|||||||
@@ -30,10 +30,36 @@ export default function HistoryChart({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const activeDataKey = activeTab.toLowerCase();
|
const activeDataKey = activeTab.toLowerCase();
|
||||||
const currentData = data[activeDataKey] || data[activeTab] || [];
|
const rawData = data[activeDataKey] || data[activeTab] || [];
|
||||||
|
const currentData = [...rawData].reverse();
|
||||||
|
|
||||||
const maxAmount = Math.max(...currentData.map((d) => d.amount), 1);
|
const maxAmount =
|
||||||
|
currentData.length > 0
|
||||||
|
? Math.max(...currentData.map((d) => d.amount), 1)
|
||||||
|
: 1;
|
||||||
|
|
||||||
|
// ✅ Formatter (₹ + adaptive units)
|
||||||
|
const formatAmount = (amount: number) => {
|
||||||
|
const tab = activeTab.toLowerCase();
|
||||||
|
|
||||||
|
if (amount === 0) return "";
|
||||||
|
|
||||||
|
if (tab === "year") {
|
||||||
|
if (amount >= 100000) {
|
||||||
|
return `₹ ${(amount / 100000).toFixed(2)} L`;
|
||||||
|
}
|
||||||
|
return `₹ ${amount.toLocaleString("en-IN")}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tab === "month") {
|
||||||
|
if (amount >= 1000) {
|
||||||
|
return `₹ ${(amount / 1000).toFixed(1)} K`;
|
||||||
|
}
|
||||||
|
return `₹ ${amount.toLocaleString("en-IN")}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `₹ ${amount.toLocaleString("en-IN")}`;
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<Paper sx={{ p: { xs: 2, sm: 4 }, borderRadius: 4, width: "100%", boxShadow: 'none', border: '1px solid', borderColor: 'divider' }}>
|
<Paper sx={{ p: { xs: 2, sm: 4 }, borderRadius: 4, width: "100%", boxShadow: 'none', border: '1px solid', borderColor: 'divider' }}>
|
||||||
<Typography variant="h6" fontWeight={700} gutterBottom>
|
<Typography variant="h6" fontWeight={700} gutterBottom>
|
||||||
@@ -83,7 +109,11 @@ export default function HistoryChart({
|
|||||||
const heightPerc = (point.amount / maxAmount) * 100;
|
const heightPerc = (point.amount / maxAmount) * 100;
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
key={point.id}
|
key={
|
||||||
|
activeTab.toLowerCase() === "month"
|
||||||
|
? point.id.replace(" - ", "\n")
|
||||||
|
: point.id
|
||||||
|
}
|
||||||
sx={{
|
sx={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
@@ -93,8 +123,18 @@ export default function HistoryChart({
|
|||||||
height: "100%",
|
height: "100%",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography variant="caption" sx={{ mb: 1, opacity: 0.7, fontSize: '0.65rem', display: { xs: 'none', sm: 'block' } }}>
|
<Typography
|
||||||
{point.amount > 0 ? `Rs ${point.amount}` : ''}
|
variant="caption"
|
||||||
|
color="text.secondary"
|
||||||
|
sx={{
|
||||||
|
mt: 1,
|
||||||
|
fontWeight: 500,
|
||||||
|
fontSize: '0.7rem',
|
||||||
|
textAlign: 'center',
|
||||||
|
whiteSpace: 'pre-line'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{point.amount > 0 ? formatAmount(point.amount) : ""}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export async function fetchLatestTransactions(
|
|||||||
|
|
||||||
return items
|
return items
|
||||||
.filter((item: any) => isValid(Number(item.amount) || 0))
|
.filter((item: any) => isValid(Number(item.amount) || 0))
|
||||||
.slice(0, 10)
|
.slice(0, 5)
|
||||||
.map((exp: any, index: number) => {
|
.map((exp: any, index: number) => {
|
||||||
const time = new Date(
|
const time = new Date(
|
||||||
exp.occurred_at || exp.created_at || Date.now()
|
exp.occurred_at || exp.created_at || Date.now()
|
||||||
@@ -77,6 +77,7 @@ export interface AggregatedDashboardData {
|
|||||||
topPayees: Array<{ payeeName: string; amount: number }>;
|
topPayees: Array<{ payeeName: string; amount: number }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------- AGGREGATION ----------------
|
||||||
// ---------------- AGGREGATION ----------------
|
// ---------------- AGGREGATION ----------------
|
||||||
export async function fetchAggregatedData(
|
export async function fetchAggregatedData(
|
||||||
type: "expense" | "income"
|
type: "expense" | "income"
|
||||||
@@ -103,7 +104,7 @@ export async function fetchAggregatedData(
|
|||||||
const weekStart = getStartOfWeek(now);
|
const weekStart = getStartOfWeek(now);
|
||||||
const weekEnd = endOfDay(new Date(weekStart.getTime() + 6 * 86400000));
|
const weekEnd = endOfDay(new Date(weekStart.getTime() + 6 * 86400000));
|
||||||
|
|
||||||
// ---------------- MONTH (5 rolling weeks) ----------------
|
// ---------------- MONTH (rolling 5 weeks, Mon–Sun aligned) ----------------
|
||||||
const monthBuckets: {
|
const monthBuckets: {
|
||||||
label: string;
|
label: string;
|
||||||
start: Date;
|
start: Date;
|
||||||
@@ -111,9 +112,11 @@ export async function fetchAggregatedData(
|
|||||||
amount: number;
|
amount: number;
|
||||||
}[] = [];
|
}[] = [];
|
||||||
|
|
||||||
|
const currentWeekStart = getStartOfWeek(now);
|
||||||
|
|
||||||
for (let i = 0; i < 5; i++) {
|
for (let i = 0; i < 5; i++) {
|
||||||
const end = endOfDay(new Date(now.getTime() - i * 7 * 86400000));
|
const start = new Date(currentWeekStart.getTime() - i * 7 * 86400000);
|
||||||
const start = startOfDay(new Date(end.getTime() - 6 * 86400000));
|
const end = endOfDay(new Date(start.getTime() + 6 * 86400000));
|
||||||
|
|
||||||
monthBuckets.push({
|
monthBuckets.push({
|
||||||
label: `${format(start)} - ${format(end)}`,
|
label: `${format(start)} - ${format(end)}`,
|
||||||
@@ -123,7 +126,7 @@ export async function fetchAggregatedData(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------- YEAR (12 months) ----------------
|
// ---------------- YEAR (rolling 12 months) ----------------
|
||||||
const yearBuckets: {
|
const yearBuckets: {
|
||||||
label: string;
|
label: string;
|
||||||
start: Date;
|
start: Date;
|
||||||
@@ -136,10 +139,18 @@ export async function fetchAggregatedData(
|
|||||||
d.setMonth(d.getMonth() - i);
|
d.setMonth(d.getMonth() - i);
|
||||||
|
|
||||||
const start = new Date(d.getFullYear(), d.getMonth(), 1);
|
const start = new Date(d.getFullYear(), d.getMonth(), 1);
|
||||||
const end = endOfDay(new Date(d.getFullYear(), d.getMonth() + 1, 0));
|
|
||||||
|
const end =
|
||||||
|
i === 0
|
||||||
|
? endOfDay(now) // current month → till now
|
||||||
|
: endOfDay(new Date(d.getFullYear(), d.getMonth() + 1, 0));
|
||||||
|
|
||||||
|
const label = `${d.toLocaleString("default", {
|
||||||
|
month: "short"
|
||||||
|
})}-${String(d.getFullYear()).slice(2)}`;
|
||||||
|
|
||||||
yearBuckets.push({
|
yearBuckets.push({
|
||||||
label: d.toLocaleString("default", { month: "short" }),
|
label,
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
amount: 0
|
amount: 0
|
||||||
@@ -170,27 +181,31 @@ export async function fetchAggregatedData(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MONTH
|
// MONTH (rolling weeks)
|
||||||
monthBuckets.forEach(b => {
|
for (const b of monthBuckets) {
|
||||||
if (d >= b.start && d <= b.end) {
|
if (d >= b.start && d <= b.end) {
|
||||||
b.amount += amt;
|
b.amount += amt;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
// YEAR
|
// YEAR (rolling months)
|
||||||
yearBuckets.forEach(b => {
|
for (const b of yearBuckets) {
|
||||||
if (d >= b.start && d <= b.end) {
|
if (d >= b.start && d <= b.end) {
|
||||||
b.amount += amt;
|
b.amount += amt;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const toPoints = (b: any): ChartDataPoint[] =>
|
const toPoints = (b: any): ChartDataPoint[] =>
|
||||||
Object.entries(b).map(([k, v]: any) => ({
|
Array.isArray(b)
|
||||||
id: k,
|
? b.map((x) => ({
|
||||||
amount: typeof v === "number" ? v : v.amount,
|
id: x.label,
|
||||||
subLabel: typeof v === "number" ? undefined : v.range
|
amount: x.amount
|
||||||
}));
|
}))
|
||||||
|
: Object.entries(b).map(([k, v]: any) => ({
|
||||||
|
id: k,
|
||||||
|
amount: v
|
||||||
|
}));
|
||||||
|
|
||||||
const chartData = {
|
const chartData = {
|
||||||
week: toPoints(weekBuckets),
|
week: toPoints(weekBuckets),
|
||||||
|
|||||||
Reference in New Issue
Block a user