Merge pull request #582 from ErikMichelson/feat/round-prices-setting
Add setting to toggle rounding of prices
This commit is contained in:
@@ -316,6 +316,10 @@
|
||||
"base_url": {
|
||||
"label": "Base URL",
|
||||
"tooltip": "The base URL to use when generating features such as QR codes."
|
||||
},
|
||||
"round_prices": {
|
||||
"label": "Round prices",
|
||||
"tooltip": "Round prices to the nearest whole number."
|
||||
}
|
||||
},
|
||||
"extra_fields": {
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
import { removeUndefined } from "../../utils/filtering";
|
||||
import { EntityType, useGetFields } from "../../utils/queryFields";
|
||||
import { TableState, useInitialTableState, useStoreInitialState } from "../../utils/saveload";
|
||||
import { useCurrency } from "../../utils/settings";
|
||||
import { useCurrencyFormatter } from "../../utils/settings";
|
||||
import { IFilament } from "./model";
|
||||
|
||||
dayjs.extend(utc);
|
||||
@@ -77,7 +77,7 @@ export const FilamentList: React.FC<IResourceComponentsProps> = () => {
|
||||
const invalidate = useInvalidate();
|
||||
const navigate = useNavigate();
|
||||
const extraFields = useGetFields(EntityType.filament);
|
||||
const currency = useCurrency();
|
||||
const currencyFormatter = useCurrencyFormatter();
|
||||
|
||||
const allColumnsWithExtraFields = [...allColumns, ...(extraFields.data?.map((field) => "extra." + field.key) ?? [])];
|
||||
|
||||
@@ -263,12 +263,10 @@ export const FilamentList: React.FC<IResourceComponentsProps> = () => {
|
||||
align: "right",
|
||||
width: 80,
|
||||
render: (_, obj: IFilamentCollapsed) => {
|
||||
return obj.price?.toLocaleString(undefined, {
|
||||
style: "currency",
|
||||
currencyDisplay: "narrowSymbol",
|
||||
currency: currency,
|
||||
notation: "compact",
|
||||
});
|
||||
if (obj.price === undefined) {
|
||||
return "";
|
||||
}
|
||||
return currencyFormatter.format(obj.price);
|
||||
},
|
||||
}),
|
||||
NumberColumn({
|
||||
|
||||
@@ -10,7 +10,7 @@ import { NumberFieldUnit } from "../../components/numberField";
|
||||
import SpoolIcon from "../../components/spoolIcon";
|
||||
import { enrichText } from "../../utils/parsing";
|
||||
import { EntityType, useGetFields } from "../../utils/queryFields";
|
||||
import { useCurrency } from "../../utils/settings";
|
||||
import { useCurrencyFormatter } from "../../utils/settings";
|
||||
import { IFilament } from "./model";
|
||||
dayjs.extend(utc);
|
||||
|
||||
@@ -20,7 +20,7 @@ export const FilamentShow: React.FC<IResourceComponentsProps> = () => {
|
||||
const t = useTranslate();
|
||||
const navigate = useNavigate();
|
||||
const extraFields = useGetFields(EntityType.filament);
|
||||
const currency = useCurrency();
|
||||
const currencyFormatter = useCurrencyFormatter();
|
||||
const { queryResult } = useShow<IFilament>({
|
||||
liveMode: "auto",
|
||||
});
|
||||
@@ -93,15 +93,7 @@ export const FilamentShow: React.FC<IResourceComponentsProps> = () => {
|
||||
<Title level={5}>{t("filament.fields.material")}</Title>
|
||||
<TextField value={record?.material} />
|
||||
<Title level={5}>{t("filament.fields.price")}</Title>
|
||||
<NumberField
|
||||
value={record?.price ?? ""}
|
||||
options={{
|
||||
style: "currency",
|
||||
currency: currency,
|
||||
currencyDisplay: "narrowSymbol",
|
||||
notation: "compact",
|
||||
}}
|
||||
/>
|
||||
<TextField value={record?.price ? currencyFormatter.format(record.price) : ""} />
|
||||
<Title level={5}>{t("filament.fields.density")}</Title>
|
||||
<NumberFieldUnit
|
||||
value={record?.density ?? ""}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useTranslate } from "@refinedev/core";
|
||||
import { Button, Form, Input, message } from "antd";
|
||||
import { Button, Checkbox, Form, Input, message } from "antd";
|
||||
import { useEffect } from "react";
|
||||
import { useGetSettings, useSetSetting } from "../../utils/querySettings";
|
||||
|
||||
@@ -7,6 +7,7 @@ export function GeneralSettings() {
|
||||
const settings = useGetSettings();
|
||||
const setBaseUrl = useSetSetting("base_url");
|
||||
const setCurrency = useSetSetting("currency");
|
||||
const setRoundPrices = useSetSetting("round_prices");
|
||||
const [form] = Form.useForm();
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const t = useTranslate();
|
||||
@@ -17,6 +18,7 @@ export function GeneralSettings() {
|
||||
form.setFieldsValue({
|
||||
currency: JSON.parse(settings.data.currency.value),
|
||||
base_url: JSON.parse(settings.data.base_url.value),
|
||||
round_prices: JSON.parse(settings.data.round_prices.value),
|
||||
});
|
||||
}
|
||||
}, [settings.data, form]);
|
||||
@@ -29,7 +31,7 @@ export function GeneralSettings() {
|
||||
}, [setCurrency.isSuccess, messageApi, t]);
|
||||
|
||||
// Handle form submit
|
||||
const onFinish = (values: { currency: string; base_url: string }) => {
|
||||
const onFinish = (values: { currency: string; base_url: string, round_prices: boolean }) => {
|
||||
// Check if the currency has changed
|
||||
if (settings.data?.currency.value !== JSON.stringify(values.currency)) {
|
||||
setCurrency.mutate(values.currency);
|
||||
@@ -38,6 +40,11 @@ export function GeneralSettings() {
|
||||
if (settings.data?.base_url.value !== JSON.stringify(values.base_url)) {
|
||||
setBaseUrl.mutate(values.base_url);
|
||||
}
|
||||
|
||||
// Check if the setting to round prices has changed
|
||||
if (settings.data?.round_prices.value !== JSON.stringify(values.round_prices)) {
|
||||
setRoundPrices.mutate(values.round_prices);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -48,6 +55,7 @@ export function GeneralSettings() {
|
||||
wrapperCol={{ span: 16 }}
|
||||
initialValues={{
|
||||
currency: settings.data?.currency.value,
|
||||
round_prices: settings.data?.round_prices.value,
|
||||
}}
|
||||
onFinish={onFinish}
|
||||
style={{
|
||||
@@ -86,6 +94,15 @@ export function GeneralSettings() {
|
||||
<Input placeholder="https://example.com:8000" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={t("settings.general.round_prices.label")}
|
||||
tooltip={t("settings.general.round_prices.tooltip")}
|
||||
name="round_prices"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Checkbox />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item wrapperCol={{ offset: 8, span: 16 }}>
|
||||
<Button type="primary" htmlType="submit" loading={settings.isFetching || setCurrency.isLoading}>
|
||||
{t("buttons.save")}
|
||||
|
||||
@@ -36,7 +36,7 @@ import {
|
||||
import { removeUndefined } from "../../utils/filtering";
|
||||
import { EntityType, useGetFields } from "../../utils/queryFields";
|
||||
import { TableState, useInitialTableState, useSavedState, useStoreInitialState } from "../../utils/saveload";
|
||||
import { useCurrency } from "../../utils/settings";
|
||||
import { useCurrencyFormatter } from "../../utils/settings";
|
||||
import { setSpoolArchived, useSpoolAdjustModal } from "./functions";
|
||||
import { ISpool } from "./model";
|
||||
|
||||
@@ -102,7 +102,7 @@ export const SpoolList: React.FC<IResourceComponentsProps> = () => {
|
||||
const invalidate = useInvalidate();
|
||||
const navigate = useNavigate();
|
||||
const extraFields = useGetFields(EntityType.spool);
|
||||
const currency = useCurrency();
|
||||
const currencyFormatter = useCurrencyFormatter();
|
||||
const { openSpoolAdjustModal, spoolAdjustModal } = useSpoolAdjustModal();
|
||||
|
||||
const allColumnsWithExtraFields = [...allColumns, ...(extraFields.data?.map((field) => "extra." + field.key) ?? [])];
|
||||
@@ -381,12 +381,10 @@ export const SpoolList: React.FC<IResourceComponentsProps> = () => {
|
||||
align: "right",
|
||||
width: 80,
|
||||
render: (_, obj: ISpoolCollapsed) => {
|
||||
return obj.price?.toLocaleString(undefined, {
|
||||
style: "currency",
|
||||
currencyDisplay: "narrowSymbol",
|
||||
currency: currency,
|
||||
notation: "compact",
|
||||
});
|
||||
if (obj.price === undefined) {
|
||||
return "";
|
||||
}
|
||||
return currencyFormatter.format(obj.price);
|
||||
},
|
||||
}),
|
||||
NumberColumn({
|
||||
|
||||
@@ -10,7 +10,7 @@ import { NumberFieldUnit } from "../../components/numberField";
|
||||
import SpoolIcon from "../../components/spoolIcon";
|
||||
import { enrichText } from "../../utils/parsing";
|
||||
import { EntityType, useGetFields } from "../../utils/queryFields";
|
||||
import { useCurrency } from "../../utils/settings";
|
||||
import { useCurrencyFormatter } from "../../utils/settings";
|
||||
import { IFilament } from "../filaments/model";
|
||||
import { setSpoolArchived } from "./functions";
|
||||
import { ISpool } from "./model";
|
||||
@@ -23,7 +23,7 @@ const { confirm } = Modal;
|
||||
export const SpoolShow: React.FC<IResourceComponentsProps> = () => {
|
||||
const t = useTranslate();
|
||||
const extraFields = useGetFields(EntityType.spool);
|
||||
const currency = useCurrency();
|
||||
const currencyFormatter = useCurrencyFormatter();
|
||||
const invalidate = useInvalidate();
|
||||
|
||||
const { queryResult } = useShow<ISpool>({
|
||||
@@ -33,13 +33,12 @@ export const SpoolShow: React.FC<IResourceComponentsProps> = () => {
|
||||
|
||||
const record = data?.data;
|
||||
|
||||
const spoolPrice = (item: ISpool) => {
|
||||
let spoolPrice = "";
|
||||
if (item.price === undefined) {
|
||||
spoolPrice = `${item.filament.price}`;
|
||||
return spoolPrice;
|
||||
const spoolPrice = (item?: ISpool) => {
|
||||
const price = item?.price ?? item?.filament.price;
|
||||
if (price === undefined) {
|
||||
return "";
|
||||
}
|
||||
return item.price;
|
||||
return currencyFormatter.format(price);
|
||||
};
|
||||
|
||||
// Function for opening an ant design modal that asks for confirmation for archiving a spool
|
||||
@@ -142,15 +141,7 @@ export const SpoolShow: React.FC<IResourceComponentsProps> = () => {
|
||||
{colorObj && <SpoolIcon color={colorObj} size="large" no_margin />}
|
||||
<TextField value={record ? filamentURL(record?.filament) : ""} />
|
||||
<Title level={5}>{t("spool.fields.price")}</Title>
|
||||
<NumberField
|
||||
value={record ? spoolPrice(record) : ""}
|
||||
options={{
|
||||
style: "currency",
|
||||
currency: currency,
|
||||
currencyDisplay: "narrowSymbol",
|
||||
notation: "compact",
|
||||
}}
|
||||
/>
|
||||
<TextField value={spoolPrice(record)} />
|
||||
<Title level={5}>{t("spool.fields.registered")}</Title>
|
||||
<DateField
|
||||
value={dayjs.utc(record?.registered).local()}
|
||||
|
||||
@@ -17,3 +17,15 @@ export function getCurrencySymbol(locale: string | undefined, currency: string)
|
||||
.replace(/\d/g, "")
|
||||
.trim();
|
||||
}
|
||||
|
||||
export function useCurrencyFormatter() {
|
||||
const currency = useCurrency();
|
||||
const roundPrices = JSON.parse(useGetSetting("round_prices").data?.value ?? "false");
|
||||
|
||||
return new Intl.NumberFormat(undefined, {
|
||||
style: "currency",
|
||||
currency: currency,
|
||||
currencyDisplay: "narrowSymbol",
|
||||
notation: roundPrices ? "compact" : "standard",
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user