Refactor: Dynamic Generation Of Category Equipment
Overview
In this article, we will discuss the refactoring of category representative equipment to improve data consistency. Currently, the system allows users to select a category representative (type="Category") when adding equipment. This can lead to the existence of multiple category representative equipment for the same category. To address this issue fundamentally, we propose changing the category representative equipment to be dynamically generated, ensuring data consistency.
Background of the Problem
Before diving into the solution, let's understand the current design's problems.
Current Design Issues
- Data Duplication: Currently, category definitions (
categories.json) and category representative equipment (equipments.jsonwheretype="Category") are managed separately, leading to potential inconsistencies. - Potential Duplication: Users can select
type="Category"when adding equipment, which may result in multiple category representatives for the same category. This duplication creates confusion and makes data management difficult. - Calculation Logic Problems: When category representatives are duplicated, they are treated as separate equipment in the scrapping list calculation. Ideally, the system should consider only the maximum value for each category, but this isn't possible with the current design.
- UI Display Issues: Multiple category representatives can compete for display in the user interface, causing a cluttered and confusing experience for the user.
Impact Areas
These issues impact several areas of the application:
src/data/equipments.json: This file contains 11 category representative equipment entries, which need to be refactored.src/components/EquipmentModal.jsx:176-177: The UI allows users to select thetypeof equipment, which needs to be modified to prevent the selection of category representatives.src/utils/calculateScrapList.js: The calculation logic treats duplicated category representatives as separate items, which needs to be updated to handle dynamically generated representatives correctly.src/utils/scrapListFormatters.js:38: The UI display might overwrite category representatives due to the potential for conflicts, requiring adjustments.
Proposed Solution
To address these problems, we propose a solution that structurally guarantees data consistency by clearly separating categories and items and dynamically generating category representative equipment.
Basic Policy
Our proposed solution revolves around a few core principles:
- Dynamic Generation of Category Representatives: Generate category representatives for all categories (official + user-defined) automatically at runtime. This ensures that there is always a single, consistent representative for each category.
- Data Schema Simplification: Remove the
typefield and category representative equipment fromequipments.json. This simplifies the data structure and eliminates the possibility of manual duplication. - Mission Schema Clarification: Add a
targetTypefield to the required equipment inmissions.json. This makes it clear whether a mission requires a specific item or a category representative. - UI Improvement: Clearly separate "Add Equipment" and "Add Category" options in the equipment management modal. This helps users understand the distinction between creating new equipment and defining new categories.
Deletion Rules (Maintaining Current Behavior)
To maintain the current functionality and user expectations, we will keep the existing deletion rules:
- Official Masters (
isMaster: true): Cannot be deleted. These are core items and categories that should always be available. - User-Defined (
isMaster: false): Can be deleted.- When a user category is deleted, all equipment within that category will also be automatically deleted (with a warning). This ensures that orphaned equipment does not remain in the system.
Detailed Specifications
Let's delve into the specifics of how we plan to implement this solution.
1. Data Schema Changes
To support dynamic generation and simplify the data structure, we need to modify the existing schemas.
equipments.json (Official Master)
Before:
{
"version": "1.0.0",
"equipments": [
{
"id": "m_eq_cat_gun_s",
"name": "Small Caliber Main Gun (Any Type)",
"categoryId": "m_cat_gun_s",
"type": "Category",
"order": 1
},
{
"id": "m_eq_gun_12cm",
"name": "12cm Single Gun",
"categoryId": "m_cat_gun_s",
"type": "Item",
"order": 100
}
]
}
After:
{
"version": "1.0.0",
"equipments": [
{
"id": "m_eq_gun_12cm",
"name": "12cm Single Gun",
"categoryId": "m_cat_gun_s",
"order": 100
}
]
}
- Remove the 11 category representative equipment entries (
type="Category"). - Remove the
typefield entirely.
missions.json
Before:
{
"reqs": [
{
"id": "req_1",
"targetId": "m_eq_cat_gun_s",
"count": 2
}
]
}
After:
{
"reqs": [
{
"id": "req_1",
"targetId": "m_cat_gun_s",
"targetType": "category",
"count": 2
},
{
"id": "req_2",
"targetId": "m_eq_gun_12cm",
"targetType": "item",
"count": 1
}
]
}
- Add a
targetTypefield ("category"|"item"). This clearly indicates whether the requirement is for a category or a specific item. - When referencing a category representative, specify the category ID directly in
targetId.
categories.json
No changes are required for this file.
2. Runtime Schema
At runtime, the system will work with the following schema:
// Category Representative (Dynamically Generated)
{
id: "m_cat_gun_s", // Use the category ID directly
name: "Small Caliber Main Gun (Any Type)",
categoryId: "m_cat_gun_s",
isMaster: true, // Inherit the category's isMaster (remove on save)
type: "Category", // Assigned during dynamic generation (remove on save)
order: 1 // Use the category's order
}
// Individual Equipment
{
id: "m_eq_gun_12cm",
name: "12cm Single Gun",
categoryId: "m_cat_gun_s",
isMaster: true, // Automatically assigned during data retrieval (remove on save)
type: "Item", // Assigned during dynamic generation (remove on save)
order: 100
}
Important: The type field will be treated similarly to isMaster.
- Automatically assigned during data loading (category representatives get
"Category", equipment gets"Item"). - Removed during saving (not included in JSON files/LocalStorage). This ensures that the
typeis always generated dynamically and not stored persistently.
3. UI Changes in the Equipment Management Modal
The user interface for managing equipment will be updated to reflect the changes in the data schema and the dynamic generation of category representatives.
New Registration Form
The new registration form will provide a clear separation between adding equipment and adding categories:
ââ New Registration âââââââââââââââââââââ
â â Add Equipment â Add Category â â Radio buttons to switch modes
â â
â ââ Add Equipment Mode (Default) ââ
â Equipment Name * â
â [12.7cm Twin Gun B Mod. 2] â
â â
â Category * â
â [Small Caliber Main Gun âŧ] â
â â
â [Add to List] â
â â
â ââ Add Category Mode ââ â
â Category Name * â
â [Custom Category A] â
â â
â âšī¸ Category representative equipment will be â
â created automatically â
â â
â [Add Category] â
âââââââââââââââââââââââââââââââââââ
The form will use radio buttons to switch between adding equipment and adding categories. When adding a category, the system will automatically create the corresponding category representative equipment.
Registered List (Maintain Current Behavior)
The display of the registered list will remain the same (showing Category and Item based on eq.type). However, it will internally include the dynamically generated category representatives.
4. Category Deletion Behavior
When a user attempts to delete a category, the system will display a confirmation dialog to ensure they understand the consequences.
Deletion Confirmation Dialog
The dialog will provide clear information about the items and missions affected by the deletion:
âââââââââââââââââââââââââââââââââââââââ
â Delete Category [Ã] â
âââââââââââââââââââââââââââââââââââââââ¤
â â
â Delete "Custom Category A"? â
â â
â â ī¸ Equipment in this category: â
â âĸ Custom Equipment A â
â âĸ Custom Equipment B â
â 2 items will be deleted â
â â
â â ī¸ Missions referencing this category: â
â âĸ Custom Mission 1 â
â âĸ Custom Mission 2 â
â This will affect 2 missions â
â (missions will not be deleted) â
â â
â This operation cannot be undone. â
â â
âââââââââââââââââââââââââââââââââââââââ¤
â [Cancel] [Delete] â
âââââââââââââââââââââââââââââââââââââââ
The dialog will list the equipment and missions that will be affected by the deletion. It will also warn the user that the operation cannot be undone.
Deletion Process
The deletion process will consist of the following steps:
- Delete the category (from LocalStorage).
- Delete all equipment belonging to that category.
- Do not clean up mission references (maintain current behavior, only display a warning).
5. Startup Validation
To ensure data integrity and compatibility, the system will perform validation checks at startup.
// utils/validation.js
export function validateAndCleanEquipments(equipments) {
const warnings = []
// Detect and remove equipment with the type field
const cleaned = equipments.filter(eq => {
if (eq.hasOwnProperty('type')) {
warnings.push({
type: 'warning',
message: `Equipment "${eq.name}" has an old format and was deleted`
})
return false
}
return true
})
return { cleaned, warnings }
}
export function validateAndCleanMissions(missions, categoryIds) {
// Auto-complete targetType (for backward compatibility)
const cleaned = missions.map(mission => ({
...mission,
reqs: mission.reqs.map(req => {
if (!req.targetType) {
const isCategory = categoryIds.includes(req.targetId)
return {
...req,
targetType: isCategory ? 'category' : 'item'
}
}
return req
})
}))
return { cleaned, warnings: [] }
}
The validation will perform the following actions:
- Remove any equipment with the old
typefield. This ensures that the system starts with a clean slate and avoids issues with outdated data. - Automatically complete the
targetTypefield in missions for backward compatibility.
6. Migration
Since this is a beta version and the release is recent, a full migration process will not be implemented. Instead, the startup validation will delete old data. This simplifies the process and avoids the complexity of migrating existing data.
Scope of Impact
The changes will affect several files and modules within the application.
| File | Change | Difficulty |
|---|---|---|
src/data/equipments.json |
Remove 11 category representatives | Low |
src/data/missions.json |
Add targetType, modify targetId to category ID |
Medium |
src/hooks/useEquipments.js |
Dynamically generate category representatives, add type assignment logic |
Medium |
src/hooks/useCategories.js |
User category support (if necessary) | Low |
src/utils/localStorage.js |
Remove type on save |
Low |
src/utils/validation.js |
Add startup validation | Medium |
src/utils/calculateScrapList.js |
targetType determination logic |
Medium |
src/components/EquipmentModal.jsx |
Add mode switching UI | Medium |
src/App.jsx |
Add category deletion processing | Medium |
src/types/schema.js |
Update schema definition | Low |
docs/schema.md |
Update schema specification | Low |
Implementation Tasks
To implement the proposed solution, we have identified the following tasks:
- [ ] Data Schema Updates
- [ ]
equipments.json: Remove 11 category representatives - [ ]
missions.json: AddtargetType, modify targetId
- [ ]
- [ ] Runtime Logic
- [ ]
useEquipments: Dynamically generate category representatives, assigntype - [ ]
localStorage: Removetypeon save - [ ]
validation: Add startup validation - [ ]
calculateScrapList:targetTypedetermination logic
- [ ]
- [ ] UI Changes
- [ ]
EquipmentModal: Add mode switching UI (Add Equipment/Add Category) - [ ]
App.jsx: Add category deletion processing
- [ ]
- [ ] Documentation Updates
- [ ]
schema.md: Update schema specification - [ ]
types/schema.js: Update TypeScript type definitions
- [ ]
- [ ] Testing
- [ ] Verify dynamic generation functionality
- [ ] Verify startup validation
- [ ] Verify category deletion functionality
- [ ] Verify mission selection and calculation logic
Benefits
This refactoring effort will yield several benefits:
- Data Consistency: Structural impossibility of category representative duplication.
- Improved Maintainability: Clearer relationship between categories and items.
- UI Improvement: No need to select
typewhen adding equipment. - Natural Deletion: Natural behavior of deleting all Items in a category when the category is deleted.
Remarks
- Due to the beta status, a migration process will not be implemented, and startup validation will delete old data.
- Schema versions will not be managed individually, but rather through overall code version upgrades.
In conclusion, by dynamically generating category representative equipment and refactoring the data schema, we can significantly improve data consistency, maintainability, and the user experience. This effort will ensure a more robust and reliable application for the future.
For more information on data consistency and refactoring best practices, you can visit a trusted website on software development. (Replace with an actual link to a relevant website).