PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.5
Yatra – Travel Booking & Tour Operator Software v3.0.5
3.0.16 3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 All 84 releases
yatra / resources / js / lib / currency-display.ts

currency-display.ts in Yatra – Travel Booking & Tour Operator Software 3.0.5, at resources/js/lib/currency-display.ts

163 lines 4.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Central currency symbol placement for Yatra admin + public UIs.
3 *
4 * Settings → Currency uses: left, right, left_space, right_space.
5 * Legacy stored values: before, after (mapped for backward compatibility).
6 */
7
8 import { __ } from "./i18n";
9 import { getCurrency, getCurrencySymbol } from "../data/currencies";
10
11 export type CurrencyPlacement = "left" | "right" | "left_space" | "right_space";
12
13 /**
14 * Normalize option / legacy values to one of the four placement modes.
15 */
16 export function normalizeCurrencyPosition(
17 raw: string | undefined | null,
18 ): CurrencyPlacement {
19 const p = (raw ?? "before").toString().toLowerCase().trim();
20 if (p === "before") {
21 return "left_space";
22 }
23 if (p === "after") {
24 return "right_space";
25 }
26 if (
27 p === "right" ||
28 p === "right_space" ||
29 p === "left" ||
30 p === "left_space"
31 ) {
32 return p as CurrencyPlacement;
33 }
34 return "left_space";
35 }
36
37 /**
38 * Join a pre-formatted numeric string with the currency symbol per placement.
39 */
40 export function applyCurrencyPosition(
41 formattedAmount: string,
42 currencySymbol: string,
43 rawPosition?: string | null,
44 ): string {
45 const mode = normalizeCurrencyPosition(rawPosition);
46 switch (mode) {
47 case "right":
48 return `${formattedAmount}${currencySymbol}`;
49 case "right_space":
50 return `${formattedAmount} ${currencySymbol}`;
51 case "left":
52 return `${currencySymbol}${formattedAmount}`;
53 case "left_space":
54 default:
55 return `${currencySymbol} ${formattedAmount}`;
56 }
57 }
58
59 type AdminWindow = Window & {
60 yatraAdmin?: Record<string, unknown>;
61 yatraBookingData?: Record<string, unknown>;
62 yatraTripData?: Record<string, unknown>;
63 yatraAccountPage?: Record<string, unknown>;
64 };
65
66 /**
67 * Read raw currency position from localized globals (camelCase or snake_case).
68 */
69 export function readYatraCurrencyPositionFromWindow(): string {
70 if (typeof window === "undefined") {
71 return "before";
72 }
73 const w = window as AdminWindow;
74 const pick = (o: Record<string, unknown> | undefined): string | undefined => {
75 if (!o) {
76 return undefined;
77 }
78 const a = o.currencyPosition;
79 const b = o.currency_position;
80 if (typeof a === "string" && a !== "") {
81 return a;
82 }
83 if (typeof b === "string" && b !== "") {
84 return b;
85 }
86 return undefined;
87 };
88
89 return (
90 pick(w.yatraAdmin as Record<string, unknown> | undefined) ??
91 pick(w.yatraBookingData as Record<string, unknown> | undefined) ??
92 pick(w.yatraTripData as Record<string, unknown> | undefined) ??
93 pick(w.yatraAccountPage as Record<string, unknown> | undefined) ??
94 "before"
95 );
96 }
97
98 function readAdminNumberFormatConfig(): {
99 decimalPlaces: number;
100 thousandSeparator: string;
101 decimalSeparator: string;
102 } {
103 if (typeof window === "undefined") {
104 return { decimalPlaces: 2, thousandSeparator: ",", decimalSeparator: "." };
105 }
106 const a = ((window as AdminWindow).yatraAdmin || {}) as Record<
107 string,
108 unknown
109 >;
110 const decimals = Number(a.decimalPlaces ?? a.currency_decimals ?? 2) || 2;
111 return {
112 decimalPlaces: Math.max(0, Math.min(4, decimals)),
113 thousandSeparator:
114 typeof a.thousandSeparator === "string" && a.thousandSeparator !== ""
115 ? (a.thousandSeparator as string)
116 : ",",
117 decimalSeparator:
118 typeof a.decimalSeparator === "string" && a.decimalSeparator !== ""
119 ? (a.decimalSeparator as string)
120 : ".",
121 };
122 }
123
124 /**
125 * Format a numeric amount using Yatra currency + separator settings and symbol placement.
126 *
127 * @param zeroAsUnknown When true, zero/empty shows “Contact for pricing” (trip/marketing UIs).
128 */
129 export function formatYatraMoney(
130 amount: number,
131 currencyCode: string,
132 options?: { zeroAsUnknown?: boolean },
133 ): string {
134 const zeroAsUnknown = options?.zeroAsUnknown === true;
135 const num = Number(amount) || 0;
136 if (zeroAsUnknown && num === 0) {
137 return __("Contact for pricing", "yatra");
138 }
139
140 const { decimalPlaces, thousandSeparator, decimalSeparator } =
141 readAdminNumberFormatConfig();
142 const currencyData = getCurrency(currencyCode);
143 const decimals =
144 currencyData?.decimalDigits !== undefined
145 ? Math.max(0, Math.min(4, currencyData.decimalDigits))
146 : decimalPlaces;
147
148 const formattedCore = new Intl.NumberFormat(undefined, {
149 minimumFractionDigits: decimals,
150 maximumFractionDigits: decimals,
151 })
152 .format(num)
153 .replace(/,/g, "TEMP_THOUSAND")
154 .replace(/\./g, "TEMP_DECIMAL")
155 .replace(/TEMP_THOUSAND/g, thousandSeparator)
156 .replace(/TEMP_DECIMAL/g, decimalSeparator);
157
158 const symbol = getCurrencySymbol(currencyCode);
159 const position = readYatraCurrencyPositionFromWindow();
160
161 return applyCurrencyPosition(formattedCore, symbol, position);
162 }
163