- {battery.brandName} {battery.typeName}
+ {battery.brandName} {battery.typeName} ({battery.chemistryName})
Total: {total} batteries
@@ -346,7 +347,7 @@ export function BatteryCard({ battery, devices }: BatteryCardProps) {
}
>
- Are you sure you want to delete {battery.brandName} {battery.typeName}?
+ Are you sure you want to delete {battery.brandName} {battery.typeName} ({battery.chemistryName})?
This action cannot be undone.
{battery.inUseCount > 0 && (
diff --git a/src/components/battery/BatteryListClient.tsx b/src/components/battery/BatteryListClient.tsx
index f1c6082..b823ef6 100644
--- a/src/components/battery/BatteryListClient.tsx
+++ b/src/components/battery/BatteryListClient.tsx
@@ -16,6 +16,11 @@ interface Brand {
name: string;
}
+interface Chemistry {
+ id: number;
+ name: string;
+}
+
interface Device {
id: number;
name: string;
@@ -25,6 +30,7 @@ interface BatteryGroup {
id: number;
brandName: string;
typeName: string;
+ chemistryName: string;
availableCount: number;
chargingCount: number;
inUseCount: number;
@@ -35,10 +41,11 @@ interface BatteryListClientProps {
batteries: BatteryGroup[];
types: BatteryType[];
brands: Brand[];
+ chemistries: Chemistry[];
devices: Device[];
}
-export function BatteryListClient({ batteries, types, brands, devices }: BatteryListClientProps) {
+export function BatteryListClient({ batteries, types, brands, chemistries, devices }: BatteryListClientProps) {
const [isAddModalOpen, setIsAddModalOpen] = useState(false);
const [filter, setFilter] = useState
('all');
@@ -107,6 +114,7 @@ export function BatteryListClient({ batteries, types, brands, devices }: Battery
onClose={() => setIsAddModalOpen(false)}
types={types}
brands={brands}
+ chemistries={chemistries}
/>
);
diff --git a/src/lib/db/schema.ts b/src/lib/db/schema.ts
index 425c35e..2056c84 100644
--- a/src/lib/db/schema.ts
+++ b/src/lib/db/schema.ts
@@ -9,6 +9,14 @@ export const batteryTypes = sqliteTable('battery_types', {
createdAt: text('created_at').default(sql`(datetime('now'))`),
});
+// Battery chemistries (NiMH, Li-ion, LiFePO4, etc.)
+export const chemistries = sqliteTable('chemistries', {
+ id: integer('id').primaryKey({ autoIncrement: true }),
+ name: text('name').notNull().unique(),
+ isCustom: integer('is_custom', { mode: 'boolean' }).default(false),
+ createdAt: text('created_at').default(sql`(datetime('now'))`),
+});
+
// Brands (Panasonic, Eneloop, etc.)
export const brands = sqliteTable('brands', {
id: integer('id').primaryKey({ autoIncrement: true }),
@@ -16,18 +24,19 @@ export const brands = sqliteTable('brands', {
createdAt: text('created_at').default(sql`(datetime('now'))`),
});
-// Battery groups (Brand + Type combination with counts)
+// Battery groups (Brand + Type + Chemistry combination with counts)
export const batteryGroups = sqliteTable('battery_groups', {
id: integer('id').primaryKey({ autoIncrement: true }),
brandId: integer('brand_id').notNull().references(() => brands.id),
typeId: integer('type_id').notNull().references(() => batteryTypes.id),
+ chemistryId: integer('chemistry_id').notNull().references(() => chemistries.id),
availableCount: integer('available_count').default(0).notNull(),
chargingCount: integer('charging_count').default(0).notNull(),
notes: text('notes'),
createdAt: text('created_at').default(sql`(datetime('now'))`),
updatedAt: text('updated_at').default(sql`(datetime('now'))`),
}, (table) => [
- uniqueIndex('brand_type_idx').on(table.brandId, table.typeId),
+ uniqueIndex('brand_type_chemistry_idx').on(table.brandId, table.typeId, table.chemistryId),
]);
// Devices
@@ -55,6 +64,10 @@ export const batteryTypesRelations = relations(batteryTypes, ({ many }) => ({
batteryGroups: many(batteryGroups),
}));
+export const chemistriesRelations = relations(chemistries, ({ many }) => ({
+ batteryGroups: many(batteryGroups),
+}));
+
export const brandsRelations = relations(brands, ({ many }) => ({
batteryGroups: many(batteryGroups),
}));
@@ -68,6 +81,10 @@ export const batteryGroupsRelations = relations(batteryGroups, ({ one, many }) =
fields: [batteryGroups.typeId],
references: [batteryTypes.id],
}),
+ chemistry: one(chemistries, {
+ fields: [batteryGroups.chemistryId],
+ references: [chemistries.id],
+ }),
deviceBatteries: many(deviceBatteries),
}));
@@ -89,6 +106,8 @@ export const deviceBatteriesRelations = relations(deviceBatteries, ({ one }) =>
// Type exports
export type BatteryType = typeof batteryTypes.$inferSelect;
export type NewBatteryType = typeof batteryTypes.$inferInsert;
+export type Chemistry = typeof chemistries.$inferSelect;
+export type NewChemistry = typeof chemistries.$inferInsert;
export type Brand = typeof brands.$inferSelect;
export type NewBrand = typeof brands.$inferInsert;
export type BatteryGroup = typeof batteryGroups.$inferSelect;
diff --git a/src/lib/db/seed.ts b/src/lib/db/seed.ts
index 9c6e70e..8a1fe98 100644
--- a/src/lib/db/seed.ts
+++ b/src/lib/db/seed.ts
@@ -37,5 +37,19 @@ for (const typeName of defaultTypes) {
}
}
+// Seed default chemistries
+const defaultChemistries = ['NiMH', 'Li-ion', 'LiFePO4', 'NiCd', 'Li-Po', 'Alkaline'];
+
+console.log('Seeding default chemistries...');
+for (const chemName of defaultChemistries) {
+ try {
+ db.insert(schema.chemistries).values({ name: chemName, isCustom: false }).run();
+ console.log(` Added: ${chemName}`);
+ } catch {
+ // Already exists, skip
+ console.log(` Skipped (exists): ${chemName}`);
+ }
+}
+
console.log('Seed complete!');
sqlite.close();