added additonal 12 gauge types
This commit is contained in:
+16
-1
@@ -117,7 +117,7 @@ const pool = databaseUrl
|
|||||||
password: postgresPassword,
|
password: postgresPassword,
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultCalibers = ['9mm', '.22 LR', '5.56 NATO', '.308 Win', '12 Gauge', '.45 ACP'];
|
const defaultCalibers = ['9mm', '.22 LR', '5.56 NATO', '.308 Win', '12 Gauge - Birdshot', '12 Gauge - Buckshot', '12 Gauge - Slug', '12 Gauge Sporting', '.45 ACP'];
|
||||||
const firearmCategories = ['Handgun', 'Rifle', 'Shotgun', 'PCC', 'Other'];
|
const firearmCategories = ['Handgun', 'Rifle', 'Shotgun', 'PCC', 'Other'];
|
||||||
const sessionHours = 24 * 7;
|
const sessionHours = 24 * 7;
|
||||||
|
|
||||||
@@ -384,6 +384,21 @@ const ensureSchema = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ensureProfileDefaults = async (profileId: string) => {
|
const ensureProfileDefaults = async (profileId: string) => {
|
||||||
|
await pool.query(
|
||||||
|
`UPDATE calibers
|
||||||
|
SET name = '12 Gauge Sporting',
|
||||||
|
is_default = TRUE
|
||||||
|
WHERE profile_id = $1
|
||||||
|
AND name = '12 Gauge'
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM calibers existing
|
||||||
|
WHERE existing.profile_id = $1
|
||||||
|
AND existing.name = '12 Gauge Sporting'
|
||||||
|
)`,
|
||||||
|
[profileId],
|
||||||
|
);
|
||||||
|
|
||||||
for (const caliber of defaultCalibers) {
|
for (const caliber of defaultCalibers) {
|
||||||
const caliberResult = await pool.query<CaliberRow>(
|
const caliberResult = await pool.query<CaliberRow>(
|
||||||
`INSERT INTO calibers (profile_id, name, is_default, is_active)
|
`INSERT INTO calibers (profile_id, name, is_default, is_active)
|
||||||
|
|||||||
@@ -117,7 +117,8 @@ const ammoPageSelectionKey = 'arsenal-iq-ammo-page-calibers';
|
|||||||
const ammoPageSelectionMigrationKey = 'arsenal-iq-ammo-page-calibers-v2';
|
const ammoPageSelectionMigrationKey = 'arsenal-iq-ammo-page-calibers-v2';
|
||||||
const firearmCategories = ['Handgun', 'Rifle', 'Shotgun', 'PCC', 'Other'];
|
const firearmCategories = ['Handgun', 'Rifle', 'Shotgun', 'PCC', 'Other'];
|
||||||
const allFirearmCategoriesLabel = 'All categories';
|
const allFirearmCategoriesLabel = 'All categories';
|
||||||
const defaultCaliberNames = ['9mm', '.22 LR', '5.56 NATO', '.308 Win', '12 Gauge', '.45 ACP'];
|
const defaultCaliberNames = ['9mm', '.22 LR', '5.56 NATO', '.308 Win', '12 Gauge - Birdshot', '12 Gauge - Buckshot', '12 Gauge - Slug', '12 Gauge Sporting', '.45 ACP'];
|
||||||
|
const boxTrackedCalibers = ['12 Gauge Sporting'];
|
||||||
|
|
||||||
const currency = new Intl.NumberFormat('en-US', {
|
const currency = new Intl.NumberFormat('en-US', {
|
||||||
style: 'currency',
|
style: 'currency',
|
||||||
@@ -189,6 +190,18 @@ const getCategorySilhouette = (category: string) => {
|
|||||||
return silhouettes[normalized] ?? silhouettes.other;
|
return silhouettes[normalized] ?? silhouettes.other;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isBoxTrackedCaliber = (caliber: string) => boxTrackedCalibers.includes(caliber);
|
||||||
|
|
||||||
|
const getAmmoUnitLabel = (caliber: string, quantity: number) => {
|
||||||
|
if (isBoxTrackedCaliber(caliber)) {
|
||||||
|
return quantity === 1 ? 'box' : 'boxes';
|
||||||
|
}
|
||||||
|
|
||||||
|
return quantity === 1 ? 'round' : 'rounds';
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAmmoUnitNoun = (caliber: string) => (isBoxTrackedCaliber(caliber) ? 'boxes' : 'rounds');
|
||||||
|
|
||||||
const resolveFirearmImageUrl = (imageUrl: string | null | undefined) => {
|
const resolveFirearmImageUrl = (imageUrl: string | null | undefined) => {
|
||||||
const trimmed = imageUrl?.trim();
|
const trimmed = imageUrl?.trim();
|
||||||
|
|
||||||
@@ -1057,7 +1070,7 @@ export default function Home() {
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="mini-stat">
|
<div className="mini-stat">
|
||||||
<span>{activeView === 'ammo' ? 'Total rounds' : 'Total firearm value'}</span>
|
<span>{activeView === 'ammo' ? 'Total ammo units' : 'Total firearm value'}</span>
|
||||||
<strong>
|
<strong>
|
||||||
{activeView === 'ammo'
|
{activeView === 'ammo'
|
||||||
? data.summary.totalAmmoRounds
|
? data.summary.totalAmmoRounds
|
||||||
@@ -1297,14 +1310,14 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{ammoChartData.length === 0 ? (
|
{ammoChartData.length === 0 ? (
|
||||||
<p className="placeholder-copy">Add rounds to a caliber to see how your inventory stacks up.</p>
|
<p className="placeholder-copy">Add ammo to a caliber to see how your inventory stacks up.</p>
|
||||||
) : (
|
) : (
|
||||||
<div className="ammo-chart">
|
<div className="ammo-chart">
|
||||||
{ammoChartData.map((inventory) => (
|
{ammoChartData.map((inventory) => (
|
||||||
<div className="ammo-chart-row" key={inventory.caliberId}>
|
<div className="ammo-chart-row" key={inventory.caliberId}>
|
||||||
<div className="ammo-chart-meta">
|
<div className="ammo-chart-meta">
|
||||||
<strong>{inventory.caliber}</strong>
|
<strong>{inventory.caliber}</strong>
|
||||||
<span>{inventory.roundsOnHand.toLocaleString()} rounds</span>
|
<span>{inventory.roundsOnHand.toLocaleString()} {getAmmoUnitLabel(inventory.caliber, inventory.roundsOnHand)}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="ammo-chart-track" aria-hidden="true">
|
<div className="ammo-chart-track" aria-hidden="true">
|
||||||
<div
|
<div
|
||||||
@@ -1320,20 +1333,20 @@ export default function Home() {
|
|||||||
|
|
||||||
<div className="ammo-grid">
|
<div className="ammo-grid">
|
||||||
{ammoPageInventory.length === 0 ? (
|
{ammoPageInventory.length === 0 ? (
|
||||||
<p className="placeholder-copy">Add an enabled caliber to start tracking rounds on this page.</p>
|
<p className="placeholder-copy">Add an enabled caliber to start tracking ammo on this page.</p>
|
||||||
) : (
|
) : (
|
||||||
ammoPageInventory.map((inventory) => (
|
ammoPageInventory.map((inventory) => (
|
||||||
<article className="ammo-card" key={inventory.caliberId}>
|
<article className="ammo-card" key={inventory.caliberId}>
|
||||||
<div className="ammo-card-top">
|
<div className="ammo-card-top">
|
||||||
<div>
|
<div>
|
||||||
<strong>{inventory.caliber}</strong>
|
<strong>{inventory.caliber}</strong>
|
||||||
<p>{inventory.roundsOnHand} rounds on hand</p>
|
<p>{inventory.roundsOnHand} {getAmmoUnitLabel(inventory.caliber, inventory.roundsOnHand)} on hand</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="form-grid compact">
|
<div className="form-grid compact">
|
||||||
<label>
|
<label>
|
||||||
<span>Round adjustment</span>
|
<span>{isBoxTrackedCaliber(inventory.caliber) ? 'Box adjustment' : 'Round adjustment'}</span>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
value={ammoAdjustments[inventory.caliberId]?.rounds ?? ''}
|
value={ammoAdjustments[inventory.caliberId]?.rounds ?? ''}
|
||||||
@@ -1352,7 +1365,7 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="card-footer">
|
<div className="card-footer">
|
||||||
<span>Enter a quantity, then update or remove rounds for this caliber.</span>
|
<span>Enter a quantity, then update or remove {getAmmoUnitNoun(inventory.caliber)} for this caliber.</span>
|
||||||
<div className="button-row">
|
<div className="button-row">
|
||||||
<button className="secondary-button" onClick={() => void adjustAmmo(inventory.caliberId, 'remove')} type="button">
|
<button className="secondary-button" onClick={() => void adjustAmmo(inventory.caliberId, 'remove')} type="button">
|
||||||
Remove ammo
|
Remove ammo
|
||||||
|
|||||||
Reference in New Issue
Block a user