feat: integrate react-number-format for price inputs in product create and edit forms
This commit is contained in:
parent
4b5d5af316
commit
bfee01153c
1799
package-lock.json
generated
1799
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -82,6 +82,7 @@
|
|||||||
"react": "^19.2.0",
|
"react": "^19.2.0",
|
||||||
"react-dom": "^19.2.0",
|
"react-dom": "^19.2.0",
|
||||||
"react-hotkeys-hook": "^5.2.4",
|
"react-hotkeys-hook": "^5.2.4",
|
||||||
|
"react-number-format": "^5.4.5",
|
||||||
"shadcn": "^4.2.0",
|
"shadcn": "^4.2.0",
|
||||||
"sonner": "^2.0.7",
|
"sonner": "^2.0.7",
|
||||||
"tailwind-merge": "^3.5.0",
|
"tailwind-merge": "^3.5.0",
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import {
|
|||||||
ComboboxValue,
|
ComboboxValue,
|
||||||
useComboboxAnchor,
|
useComboboxAnchor,
|
||||||
} from "@/components/ui/combobox"
|
} from "@/components/ui/combobox"
|
||||||
|
import { NumericFormat } from 'react-number-format';
|
||||||
|
|
||||||
export default function ProductCreate({ categories }: { categories: Category[] }) {
|
export default function ProductCreate({ categories }: { categories: Category[] }) {
|
||||||
const { data, setData, post, processing, errors } = useForm({
|
const { data, setData, post, processing, errors } = useForm({
|
||||||
@ -122,65 +123,100 @@ export default function ProductCreate({ categories }: { categories: Category[] }
|
|||||||
|
|
||||||
<Field>
|
<Field>
|
||||||
<Label htmlFor="price_purchase">Harga Beli</Label>
|
<Label htmlFor="price_purchase">Harga Beli</Label>
|
||||||
<Input
|
<NumericFormat
|
||||||
id="price_purchase"
|
id="price_purchase"
|
||||||
type="number"
|
customInput={Input}
|
||||||
min="0"
|
thousandSeparator="."
|
||||||
|
decimalSeparator=","
|
||||||
|
prefix="Rp "
|
||||||
value={data.prices.purchase}
|
value={data.prices.purchase}
|
||||||
onChange={e => setData('prices', { ...data.prices, purchase: e.target.value })}
|
onValueChange={(values) => {
|
||||||
placeholder='0'
|
setData('prices', {
|
||||||
|
...data.prices,
|
||||||
|
purchase: values.value
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
placeholder="Rp 0"
|
||||||
/>
|
/>
|
||||||
{errors['prices.purchase'] && <p className="text-xs text-red-500">{errors['prices.purchase']}</p>}
|
{errors['prices.purchase'] && <p className="text-xs text-red-500">{errors['prices.purchase']}</p>}
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
<Field>
|
<Field>
|
||||||
<Label htmlFor="price_distributor">Harga Distributor</Label>
|
<Label htmlFor="price_distributor">Harga Distributor</Label>
|
||||||
<Input
|
<NumericFormat
|
||||||
id="price_distributor"
|
id="price_distributor"
|
||||||
type="number"
|
customInput={Input}
|
||||||
min="0"
|
thousandSeparator="."
|
||||||
|
decimalSeparator=","
|
||||||
|
prefix="Rp "
|
||||||
value={data.prices.distributor}
|
value={data.prices.distributor}
|
||||||
onChange={e => setData('prices', { ...data.prices, distributor: e.target.value })}
|
onValueChange={(values) => {
|
||||||
placeholder='0'
|
setData('prices', {
|
||||||
|
...data.prices,
|
||||||
|
distributor: values.value
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
placeholder="Rp 0"
|
||||||
/>
|
/>
|
||||||
{errors['prices.distributor'] && <p className="text-xs text-red-500">{errors['prices.distributor']}</p>}
|
{errors['prices.distributor'] && <p className="text-xs text-red-500">{errors['prices.distributor']}</p>}
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
<Field>
|
<Field>
|
||||||
<Label htmlFor="price_agent">Harga Agen</Label>
|
<Label htmlFor="price_agent">Harga Agen</Label>
|
||||||
<Input
|
<NumericFormat
|
||||||
id="price_agent"
|
id="price_agent"
|
||||||
type="number"
|
customInput={Input}
|
||||||
min="0"
|
thousandSeparator="."
|
||||||
|
decimalSeparator=","
|
||||||
|
prefix="Rp "
|
||||||
value={data.prices.agent}
|
value={data.prices.agent}
|
||||||
onChange={e => setData('prices', { ...data.prices, agent: e.target.value })}
|
onValueChange={(values) => {
|
||||||
placeholder='0'
|
setData('prices', {
|
||||||
|
...data.prices,
|
||||||
|
agent: values.value
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
placeholder="Rp 0"
|
||||||
/>
|
/>
|
||||||
{errors['prices.agent'] && <p className="text-xs text-red-500">{errors['prices.agent']}</p>}
|
{errors['prices.agent'] && <p className="text-xs text-red-500">{errors['prices.agent']}</p>}
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
<Field>
|
<Field>
|
||||||
<Label htmlFor="price_reseller">Harga Reseller</Label>
|
<Label htmlFor="price_reseller">Harga Reseller</Label>
|
||||||
<Input
|
<NumericFormat
|
||||||
id="price_reseller"
|
id="price_reseller"
|
||||||
type="number"
|
customInput={Input}
|
||||||
min="0"
|
thousandSeparator="."
|
||||||
|
decimalSeparator=","
|
||||||
|
prefix="Rp "
|
||||||
value={data.prices.reseller}
|
value={data.prices.reseller}
|
||||||
onChange={e => setData('prices', { ...data.prices, reseller: e.target.value })}
|
onValueChange={(values) => {
|
||||||
placeholder='0'
|
setData('prices', {
|
||||||
|
...data.prices,
|
||||||
|
reseller: values.value
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
placeholder="Rp 0"
|
||||||
/>
|
/>
|
||||||
{errors['prices.reseller'] && <p className="text-xs text-red-500">{errors['prices.reseller']}</p>}
|
{errors['prices.reseller'] && <p className="text-xs text-red-500">{errors['prices.reseller']}</p>}
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
<Field>
|
<Field>
|
||||||
<Label htmlFor="price_retail">Harga Retail</Label>
|
<Label htmlFor="price_retail">Harga Retail</Label>
|
||||||
<Input
|
<NumericFormat
|
||||||
id="price_retail"
|
id="price_retail"
|
||||||
type="number"
|
customInput={Input}
|
||||||
min="0"
|
thousandSeparator="."
|
||||||
|
decimalSeparator=","
|
||||||
|
prefix="Rp "
|
||||||
value={data.prices.retail}
|
value={data.prices.retail}
|
||||||
onChange={e => setData('prices', { ...data.prices, retail: e.target.value })}
|
onValueChange={(values) => {
|
||||||
placeholder='0'
|
setData('prices', {
|
||||||
|
...data.prices,
|
||||||
|
retail: values.value
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
placeholder="Rp 0"
|
||||||
/>
|
/>
|
||||||
{errors['prices.retail'] && <p className="text-xs text-red-500">{errors['prices.retail']}</p>}
|
{errors['prices.retail'] && <p className="text-xs text-red-500">{errors['prices.retail']}</p>}
|
||||||
</Field>
|
</Field>
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import {
|
|||||||
ComboboxValue,
|
ComboboxValue,
|
||||||
useComboboxAnchor,
|
useComboboxAnchor,
|
||||||
} from "@/components/ui/combobox"
|
} from "@/components/ui/combobox"
|
||||||
|
import { NumericFormat } from 'react-number-format';
|
||||||
|
|
||||||
export default function ProductEdit({ product, categories }: { product: Product, categories: Category[] }) {
|
export default function ProductEdit({ product, categories }: { product: Product, categories: Category[] }) {
|
||||||
const getPrice = (type: string) => {
|
const getPrice = (type: string) => {
|
||||||
@ -130,65 +131,100 @@ export default function ProductEdit({ product, categories }: { product: Product,
|
|||||||
|
|
||||||
<Field>
|
<Field>
|
||||||
<Label htmlFor="price_purchase">Harga Beli</Label>
|
<Label htmlFor="price_purchase">Harga Beli</Label>
|
||||||
<Input
|
<NumericFormat
|
||||||
id="price_purchase"
|
id="price_purchase"
|
||||||
type="number"
|
customInput={Input}
|
||||||
min="0"
|
thousandSeparator="."
|
||||||
|
decimalSeparator=","
|
||||||
|
prefix="Rp "
|
||||||
value={data.prices.purchase}
|
value={data.prices.purchase}
|
||||||
onChange={e => setData('prices', { ...data.prices, purchase: e.target.value })}
|
onValueChange={(values) => {
|
||||||
placeholder='0'
|
setData('prices', {
|
||||||
|
...data.prices,
|
||||||
|
purchase: values.value
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
placeholder="Rp 0"
|
||||||
/>
|
/>
|
||||||
{errors['prices.purchase'] && <p className="text-xs text-red-500">{errors['prices.purchase']}</p>}
|
{errors['prices.purchase'] && <p className="text-xs text-red-500">{errors['prices.purchase']}</p>}
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
<Field>
|
<Field>
|
||||||
<Label htmlFor="price_distributor">Harga Distributor</Label>
|
<Label htmlFor="price_distributor">Harga Distributor</Label>
|
||||||
<Input
|
<NumericFormat
|
||||||
id="price_distributor"
|
id="price_distributor"
|
||||||
type="number"
|
customInput={Input}
|
||||||
min="0"
|
thousandSeparator="."
|
||||||
|
decimalSeparator=","
|
||||||
|
prefix="Rp "
|
||||||
value={data.prices.distributor}
|
value={data.prices.distributor}
|
||||||
onChange={e => setData('prices', { ...data.prices, distributor: e.target.value })}
|
onValueChange={(values) => {
|
||||||
placeholder='0'
|
setData('prices', {
|
||||||
|
...data.prices,
|
||||||
|
distributor: values.value
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
placeholder="Rp 0"
|
||||||
/>
|
/>
|
||||||
{errors['prices.distributor'] && <p className="text-xs text-red-500">{errors['prices.distributor']}</p>}
|
{errors['prices.distributor'] && <p className="text-xs text-red-500">{errors['prices.distributor']}</p>}
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
<Field>
|
<Field>
|
||||||
<Label htmlFor="price_agent">Harga Agen</Label>
|
<Label htmlFor="price_agent">Harga Agen</Label>
|
||||||
<Input
|
<NumericFormat
|
||||||
id="price_agent"
|
id="price_agent"
|
||||||
type="number"
|
customInput={Input}
|
||||||
min="0"
|
thousandSeparator="."
|
||||||
|
decimalSeparator=","
|
||||||
|
prefix="Rp "
|
||||||
value={data.prices.agent}
|
value={data.prices.agent}
|
||||||
onChange={e => setData('prices', { ...data.prices, agent: e.target.value })}
|
onValueChange={(values) => {
|
||||||
placeholder='0'
|
setData('prices', {
|
||||||
|
...data.prices,
|
||||||
|
agent: values.value
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
placeholder="Rp 0"
|
||||||
/>
|
/>
|
||||||
{errors['prices.agent'] && <p className="text-xs text-red-500">{errors['prices.agent']}</p>}
|
{errors['prices.agent'] && <p className="text-xs text-red-500">{errors['prices.agent']}</p>}
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
<Field>
|
<Field>
|
||||||
<Label htmlFor="price_reseller">Harga Reseller</Label>
|
<Label htmlFor="price_reseller">Harga Reseller</Label>
|
||||||
<Input
|
<NumericFormat
|
||||||
id="price_reseller"
|
id="price_reseller"
|
||||||
type="number"
|
customInput={Input}
|
||||||
min="0"
|
thousandSeparator="."
|
||||||
|
decimalSeparator=","
|
||||||
|
prefix="Rp "
|
||||||
value={data.prices.reseller}
|
value={data.prices.reseller}
|
||||||
onChange={e => setData('prices', { ...data.prices, reseller: e.target.value })}
|
onValueChange={(values) => {
|
||||||
placeholder='0'
|
setData('prices', {
|
||||||
|
...data.prices,
|
||||||
|
reseller: values.value
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
placeholder="Rp 0"
|
||||||
/>
|
/>
|
||||||
{errors['prices.reseller'] && <p className="text-xs text-red-500">{errors['prices.reseller']}</p>}
|
{errors['prices.reseller'] && <p className="text-xs text-red-500">{errors['prices.reseller']}</p>}
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
<Field>
|
<Field>
|
||||||
<Label htmlFor="price_retail">Harga Retail</Label>
|
<Label htmlFor="price_retail">Harga Retail</Label>
|
||||||
<Input
|
<NumericFormat
|
||||||
id="price_retail"
|
id="price_retail"
|
||||||
type="number"
|
customInput={Input}
|
||||||
min="0"
|
thousandSeparator="."
|
||||||
|
decimalSeparator=","
|
||||||
|
prefix="Rp "
|
||||||
value={data.prices.retail}
|
value={data.prices.retail}
|
||||||
onChange={e => setData('prices', { ...data.prices, retail: e.target.value })}
|
onValueChange={(values) => {
|
||||||
placeholder='0'
|
setData('prices', {
|
||||||
|
...data.prices,
|
||||||
|
retail: values.value
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
placeholder="Rp 0"
|
||||||
/>
|
/>
|
||||||
{errors['prices.retail'] && <p className="text-xs text-red-500">{errors['prices.retail']}</p>}
|
{errors['prices.retail'] && <p className="text-xs text-red-500">{errors['prices.retail']}</p>}
|
||||||
</Field>
|
</Field>
|
||||||
|
|||||||
@ -4,6 +4,11 @@ import tailwindcss from '@tailwindcss/vite';
|
|||||||
import react from '@vitejs/plugin-react';
|
import react from '@vitejs/plugin-react';
|
||||||
import laravel from 'laravel-vite-plugin';
|
import laravel from 'laravel-vite-plugin';
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
@ -13,13 +18,24 @@ export default defineConfig({
|
|||||||
}),
|
}),
|
||||||
inertia(),
|
inertia(),
|
||||||
react({
|
react({
|
||||||
babel: {
|
// Babel compiler can sometimes cause issues with third-party hooks in React 19
|
||||||
plugins: ['babel-plugin-react-compiler'],
|
// babel: {
|
||||||
},
|
// plugins: ['babel-plugin-react-compiler'],
|
||||||
|
// },
|
||||||
}),
|
}),
|
||||||
tailwindcss(),
|
tailwindcss(),
|
||||||
wayfinder({
|
wayfinder({
|
||||||
formVariants: true,
|
formVariants: true,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'react': path.resolve(__dirname, 'node_modules/react'),
|
||||||
|
'react-dom': path.resolve(__dirname, 'node_modules/react-dom'),
|
||||||
|
'@': path.resolve(__dirname, 'resources/js'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
optimizeDeps: {
|
||||||
|
include: ['react-number-format'],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user