feat: Add comprehensive i18n support to QualityTemplateWizard
Added full internationalization support for the Quality Template wizard: Translation keys added (en/es/eu): - Scoring methods (weighted average, pass/fail, percentage, points-based) - Advanced fields (check points, parameters, thresholds, scoring criteria) - Section headers (check points config, advanced config, responsibility, control settings) - Control settings (active template, photo evidence, critical control point, notify on failure) Component updates: - Translated all hardcoded strings in QualityTemplateWizard.tsx - Implemented useTranslation hook - Updated all labels, placeholders, tooltips, and section headers - Added translations for scoring configuration section - Translated advanced options including JSONB configuration fields - Translated responsibility & requirements section - Translated control settings checkboxes Follows established pattern from InventoryWizard.tsx for consistency.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { WizardStep, WizardStepProps } from '../../../ui/WizardModal/WizardModal';
|
||||
import { AdvancedOptionsSection } from '../../../ui/AdvancedOptionsSection';
|
||||
import Tooltip from '../../../ui/Tooltip/Tooltip';
|
||||
@@ -11,6 +12,7 @@ interface WizardDataProps extends WizardStepProps {
|
||||
|
||||
// Single comprehensive step with all fields
|
||||
const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange }) => {
|
||||
const { t } = useTranslation('wizards');
|
||||
const [templateData, setTemplateData] = useState({
|
||||
// Required fields
|
||||
name: data.name || '',
|
||||
@@ -60,10 +62,10 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
<div className="space-y-6">
|
||||
<div className="text-center pb-4 border-b border-[var(--border-primary)]">
|
||||
<h3 className="text-lg font-semibold text-[var(--text-primary)] mb-2">
|
||||
Quality Template Details
|
||||
{t('qualityTemplate.templateDetails')}
|
||||
</h3>
|
||||
<p className="text-sm text-[var(--text-secondary)]">
|
||||
Fill in the required information to create a quality check template
|
||||
{t('qualityTemplate.fillRequiredInfo')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -71,40 +73,40 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="md:col-span-2">
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Name *
|
||||
{t('qualityTemplate.fields.name')} *
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={templateData.name}
|
||||
onChange={(e) => handleDataChange({ ...templateData, name: e.target.value })}
|
||||
placeholder="E.g., Bread Quality Control, Hygiene Inspection"
|
||||
placeholder={t('qualityTemplate.fields.namePlaceholder')}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Check Type *
|
||||
{t('qualityTemplate.fields.checkType')} *
|
||||
</label>
|
||||
<select
|
||||
value={templateData.checkType}
|
||||
onChange={(e) => handleDataChange({ ...templateData, checkType: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
>
|
||||
<option value="product_quality">Product Quality</option>
|
||||
<option value="process_hygiene">Process Hygiene</option>
|
||||
<option value="equipment">Equipment</option>
|
||||
<option value="safety">Safety</option>
|
||||
<option value="cleaning">Cleaning</option>
|
||||
<option value="temperature">Temperature Control</option>
|
||||
<option value="documentation">Documentation</option>
|
||||
<option value="product_quality">{t('qualityTemplate.checkTypes.product_quality')}</option>
|
||||
<option value="process_hygiene">{t('qualityTemplate.checkTypes.process_hygiene')}</option>
|
||||
<option value="equipment">{t('qualityTemplate.checkTypes.equipment')}</option>
|
||||
<option value="safety">{t('qualityTemplate.checkTypes.safety')}</option>
|
||||
<option value="cleaning">{t('qualityTemplate.checkTypes.cleaning')}</option>
|
||||
<option value="temperature">{t('qualityTemplate.checkTypes.temperature')}</option>
|
||||
<option value="documentation">{t('qualityTemplate.checkTypes.documentation')}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Weight *
|
||||
<Tooltip content="Importance weight for scoring (0.0-10.0)">
|
||||
{t('qualityTemplate.fields.weight')} *
|
||||
<Tooltip content={t('qualityTemplate.fields.weightTooltip')}>
|
||||
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
|
||||
</Tooltip>
|
||||
</label>
|
||||
@@ -123,12 +125,12 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
|
||||
{/* Basic Information */}
|
||||
<div className="border-t border-[var(--border-primary)] pt-4">
|
||||
<h4 className="text-sm font-semibold text-[var(--text-primary)] mb-3">Basic Information</h4>
|
||||
<h4 className="text-sm font-semibold text-[var(--text-primary)] mb-3">{t('qualityTemplate.sections.basicInformation')}</h4>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Template Code (Optional)
|
||||
<Tooltip content="Leave empty to auto-generate from backend, or enter custom code">
|
||||
{t('qualityTemplate.fields.templateCode')} ({t('common.optional')})
|
||||
<Tooltip content={t('qualityTemplate.fields.templateCodeTooltip')}>
|
||||
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
|
||||
</Tooltip>
|
||||
</label>
|
||||
@@ -136,14 +138,14 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
type="text"
|
||||
value={templateData.templateCode}
|
||||
onChange={(e) => handleDataChange({ ...templateData, templateCode: e.target.value })}
|
||||
placeholder="Leave empty for auto-generation"
|
||||
placeholder={t('qualityTemplate.fields.templateCodePlaceholder')}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Version
|
||||
{t('qualityTemplate.fields.version')}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
@@ -156,12 +158,12 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
|
||||
<div className="md:col-span-2">
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Description
|
||||
{t('qualityTemplate.fields.description')}
|
||||
</label>
|
||||
<textarea
|
||||
value={templateData.description}
|
||||
onChange={(e) => handleDataChange({ ...templateData, description: e.target.value })}
|
||||
placeholder="Detailed description of the quality check template"
|
||||
placeholder={t('qualityTemplate.fields.descriptionPlaceholder')}
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -169,8 +171,8 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
|
||||
<div className="md:col-span-2">
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Applicable Stages
|
||||
<Tooltip content="Comma-separated list of production stages: e.g., mixing, proofing, baking, cooling">
|
||||
{t('qualityTemplate.fields.applicableStages')}
|
||||
<Tooltip content={t('qualityTemplate.fields.applicableStagesTooltip')}>
|
||||
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
|
||||
</Tooltip>
|
||||
</label>
|
||||
@@ -178,7 +180,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
type="text"
|
||||
value={templateData.applicableStages}
|
||||
onChange={(e) => handleDataChange({ ...templateData, applicableStages: e.target.value })}
|
||||
placeholder="mixing, proofing, baking, cooling"
|
||||
placeholder={t('qualityTemplate.fields.applicablePlaceholder')}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
</div>
|
||||
@@ -187,28 +189,28 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
|
||||
{/* Scoring Configuration */}
|
||||
<div className="border-t border-[var(--border-primary)] pt-4">
|
||||
<h4 className="text-sm font-semibold text-[var(--text-primary)] mb-3">Scoring Configuration</h4>
|
||||
<h4 className="text-sm font-semibold text-[var(--text-primary)] mb-3">{t('qualityTemplate.sections.scoringConfiguration')}</h4>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Scoring Method
|
||||
{t('qualityTemplate.scoringMethods.scoringMethod')}
|
||||
</label>
|
||||
<select
|
||||
value={templateData.scoringMethod}
|
||||
onChange={(e) => handleDataChange({ ...templateData, scoringMethod: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
>
|
||||
<option value="weighted_average">Weighted Average</option>
|
||||
<option value="pass_fail">Pass/Fail</option>
|
||||
<option value="percentage">Percentage</option>
|
||||
<option value="points">Points-based</option>
|
||||
<option value="weighted_average">{t('qualityTemplate.scoringMethods.weightedAverage')}</option>
|
||||
<option value="pass_fail">{t('qualityTemplate.scoringMethods.passFail')}</option>
|
||||
<option value="percentage">{t('qualityTemplate.scoringMethods.percentage')}</option>
|
||||
<option value="points">{t('qualityTemplate.scoringMethods.pointsBased')}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Pass Threshold (%)
|
||||
<Tooltip content="Minimum score required to pass (0-100)">
|
||||
{t('qualityTemplate.advancedFields.passThresholdPercent')}
|
||||
<Tooltip content={t('tooltips.passThreshold')}>
|
||||
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
|
||||
</Tooltip>
|
||||
</label>
|
||||
@@ -226,8 +228,8 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Frequency (days)
|
||||
<Tooltip content="How often this check should be performed (leave empty for batch-based)">
|
||||
{t('qualityTemplate.advancedFields.frequencyDays')}
|
||||
<Tooltip content={t('tooltips.frequencyDays')}>
|
||||
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
|
||||
</Tooltip>
|
||||
</label>
|
||||
@@ -235,7 +237,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
type="number"
|
||||
value={templateData.frequencyDays}
|
||||
onChange={(e) => handleDataChange({ ...templateData, frequencyDays: e.target.value })}
|
||||
placeholder="Leave empty for batch-based"
|
||||
placeholder={t('qualityTemplate.advancedFields.frequencyPlaceholder')}
|
||||
min="1"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -249,7 +251,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
|
||||
/>
|
||||
<label className="text-sm text-[var(--text-secondary)]">
|
||||
Required Check
|
||||
{t('qualityTemplate.advancedFields.requiredCheck')}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -257,26 +259,26 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
|
||||
{/* Advanced Options */}
|
||||
<AdvancedOptionsSection
|
||||
title="Advanced Options"
|
||||
description="Optional fields for comprehensive quality template configuration"
|
||||
title={t('qualityTemplate.sections.advancedOptions')}
|
||||
description={t('qualityTemplate.sections.advancedOptionsDescription')}
|
||||
>
|
||||
{/* Check Points Configuration */}
|
||||
<div className="space-y-4">
|
||||
<h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">
|
||||
Check Points Configuration
|
||||
{t('qualityTemplate.sections.checkPointsConfiguration')}
|
||||
</h5>
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Check Points (JSON Array)
|
||||
<Tooltip content='Array of check points: [{"name": "Visual Check", "description": "...", "weight": 1.0}]'>
|
||||
{t('qualityTemplate.advancedFields.checkPointsJsonArray')}
|
||||
<Tooltip content={t('qualityTemplate.advancedFields.checkPointsTooltip')}>
|
||||
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
|
||||
</Tooltip>
|
||||
</label>
|
||||
<textarea
|
||||
value={templateData.checkPoints}
|
||||
onChange={(e) => handleDataChange({ ...templateData, checkPoints: e.target.value })}
|
||||
placeholder='[{"name": "Visual Inspection", "description": "Check appearance", "expected_value": "Golden brown", "measurement_type": "visual", "is_critical": false, "weight": 1.0}]'
|
||||
placeholder={t('qualityTemplate.advancedFields.checkPointsPlaceholder')}
|
||||
rows={4}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)] font-mono text-xs"
|
||||
/>
|
||||
@@ -284,12 +286,12 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Acceptance Criteria
|
||||
{t('qualityTemplate.advancedFields.acceptanceCriteria')}
|
||||
</label>
|
||||
<textarea
|
||||
value={templateData.acceptanceCriteria}
|
||||
onChange={(e) => handleDataChange({ ...templateData, acceptanceCriteria: e.target.value })}
|
||||
placeholder="E.g., Golden uniform color, fluffy texture, no burns..."
|
||||
placeholder={t('qualityTemplate.advancedFields.acceptanceCriteriaPlaceholder')}
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -300,20 +302,20 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
{/* JSONB Configuration Fields */}
|
||||
<div className="space-y-4 border-t border-[var(--border-primary)] pt-4">
|
||||
<h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">
|
||||
Advanced Configuration (JSONB)
|
||||
{t('qualityTemplate.sections.advancedConfiguration')}
|
||||
</h5>
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Parameters (JSON)
|
||||
<Tooltip content='Template parameters: {"temp_min": 75, "temp_max": 85, "humidity": 65}'>
|
||||
{t('qualityTemplate.advancedFields.parametersJson')}
|
||||
<Tooltip content={t('qualityTemplate.advancedFields.parametersTooltip')}>
|
||||
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
|
||||
</Tooltip>
|
||||
</label>
|
||||
<textarea
|
||||
value={templateData.parameters}
|
||||
onChange={(e) => handleDataChange({ ...templateData, parameters: e.target.value })}
|
||||
placeholder='{"temp_min": 75, "temp_max": 85, "humidity": 65}'
|
||||
placeholder={t('qualityTemplate.advancedFields.parametersPlaceholder')}
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)] font-mono text-xs"
|
||||
/>
|
||||
@@ -321,15 +323,15 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Thresholds (JSON)
|
||||
<Tooltip content='Threshold values: {"critical": 90, "warning": 70, "acceptable": 50}'>
|
||||
{t('qualityTemplate.advancedFields.thresholdsJson')}
|
||||
<Tooltip content={t('qualityTemplate.advancedFields.thresholdsTooltip')}>
|
||||
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
|
||||
</Tooltip>
|
||||
</label>
|
||||
<textarea
|
||||
value={templateData.thresholds}
|
||||
onChange={(e) => handleDataChange({ ...templateData, thresholds: e.target.value })}
|
||||
placeholder='{"critical": 90, "warning": 70, "acceptable": 50}'
|
||||
placeholder={t('qualityTemplate.advancedFields.thresholdsPlaceholder')}
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)] font-mono text-xs"
|
||||
/>
|
||||
@@ -337,15 +339,15 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Scoring Criteria (JSON)
|
||||
<Tooltip content='Custom scoring criteria: {"appearance": 30, "texture": 30, "taste": 40}'>
|
||||
{t('qualityTemplate.advancedFields.scoringCriteriaJson')}
|
||||
<Tooltip content={t('qualityTemplate.advancedFields.scoringCriteriaTooltip')}>
|
||||
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
|
||||
</Tooltip>
|
||||
</label>
|
||||
<textarea
|
||||
value={templateData.scoringCriteria}
|
||||
onChange={(e) => handleDataChange({ ...templateData, scoringCriteria: e.target.value })}
|
||||
placeholder='{"appearance": 30, "texture": 30, "taste": 40}'
|
||||
placeholder={t('qualityTemplate.advancedFields.scoringCriteriaPlaceholder')}
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)] font-mono text-xs"
|
||||
/>
|
||||
@@ -356,43 +358,43 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
{/* Responsibility & Requirements */}
|
||||
<div className="space-y-4 border-t border-[var(--border-primary)] pt-4">
|
||||
<h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">
|
||||
Responsibility & Requirements
|
||||
{t('qualityTemplate.sections.responsibilityRequirements')}
|
||||
</h5>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Responsible Role/Person
|
||||
{t('qualityTemplate.advancedFields.responsibleRole')}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={templateData.responsibleRole}
|
||||
onChange={(e) => handleDataChange({ ...templateData, responsibleRole: e.target.value })}
|
||||
placeholder="E.g., Production Manager, Baker"
|
||||
placeholder={t('qualityTemplate.advancedFields.responsibleRolePlaceholder')}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Required Equipment/Tools
|
||||
{t('qualityTemplate.advancedFields.requiredEquipment')}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={templateData.requiredEquipment}
|
||||
onChange={(e) => handleDataChange({ ...templateData, requiredEquipment: e.target.value })}
|
||||
placeholder="E.g., Thermometer, scale, timer"
|
||||
placeholder={t('qualityTemplate.advancedFields.requiredEquipmentPlaceholder')}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="md:col-span-2">
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Specific Conditions or Notes
|
||||
{t('qualityTemplate.advancedFields.specificConditions')}
|
||||
</label>
|
||||
<textarea
|
||||
value={templateData.specificConditions}
|
||||
onChange={(e) => handleDataChange({ ...templateData, specificConditions: e.target.value })}
|
||||
placeholder="E.g., Only applicable on humid days, check 30 min after baking..."
|
||||
placeholder={t('qualityTemplate.advancedFields.specificConditionsPlaceholder')}
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -403,7 +405,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
{/* Control Settings */}
|
||||
<div className="space-y-4 border-t border-[var(--border-primary)] pt-4">
|
||||
<h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">
|
||||
Control Settings
|
||||
{t('qualityTemplate.sections.controlSettings')}
|
||||
</h5>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -414,7 +416,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
|
||||
/>
|
||||
<label className="text-sm text-[var(--text-secondary)]">
|
||||
Active Template
|
||||
{t('qualityTemplate.advancedFields.activeTemplate')}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -426,7 +428,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
|
||||
/>
|
||||
<label className="text-sm text-[var(--text-secondary)]">
|
||||
Requires Photo Evidence
|
||||
{t('qualityTemplate.advancedFields.requiresPhotoEvidence')}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -438,7 +440,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
|
||||
/>
|
||||
<label className="text-sm text-[var(--text-secondary)]">
|
||||
Critical Control Point (CCP)
|
||||
{t('qualityTemplate.advancedFields.criticalControlPoint')}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -450,7 +452,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
|
||||
/>
|
||||
<label className="text-sm text-[var(--text-secondary)]">
|
||||
Notify on Failure
|
||||
{t('qualityTemplate.advancedFields.notifyOnFailure')}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -466,7 +468,7 @@ export const QualityTemplateWizardSteps = (
|
||||
): WizardStep[] => [
|
||||
{
|
||||
id: 'template-details',
|
||||
title: 'Template Details',
|
||||
title: 'qualityTemplate.advancedFields.templateDetailsTitle',
|
||||
component: (props) => <QualityTemplateDetailsStep {...props} data={data} onDataChange={setData} />,
|
||||
validate: () => {
|
||||
return !!(data.name && data.checkType && data.weight);
|
||||
|
||||
@@ -163,7 +163,49 @@
|
||||
"basicInformation": "Basic Information",
|
||||
"scoringConfiguration": "Scoring Configuration",
|
||||
"advancedOptions": "Advanced Options",
|
||||
"advancedOptionsDescription": "Optional fields for comprehensive quality template configuration"
|
||||
"advancedOptionsDescription": "Optional fields for comprehensive quality template configuration",
|
||||
"checkPointsConfiguration": "Check Points Configuration",
|
||||
"advancedConfiguration": "Advanced Configuration (JSONB)",
|
||||
"responsibilityRequirements": "Responsibility & Requirements",
|
||||
"controlSettings": "Control Settings"
|
||||
},
|
||||
"scoringMethods": {
|
||||
"scoringMethod": "Scoring Method",
|
||||
"weightedAverage": "Weighted Average",
|
||||
"passFail": "Pass/Fail",
|
||||
"percentage": "Percentage",
|
||||
"pointsBased": "Points-based"
|
||||
},
|
||||
"advancedFields": {
|
||||
"checkPointsJsonArray": "Check Points (JSON Array)",
|
||||
"checkPointsTooltip": "Array of check points: [{\"name\": \"Visual Check\", \"description\": \"...\", \"weight\": 1.0}]",
|
||||
"checkPointsPlaceholder": "[{\"name\": \"Visual Inspection\", \"description\": \"Check appearance\", \"expected_value\": \"Golden brown\", \"measurement_type\": \"visual\", \"is_critical\": false, \"weight\": 1.0}]",
|
||||
"acceptanceCriteria": "Acceptance Criteria",
|
||||
"acceptanceCriteriaPlaceholder": "E.g., Golden uniform color, fluffy texture, no burns...",
|
||||
"parametersJson": "Parameters (JSON)",
|
||||
"parametersTooltip": "Template parameters: {\"temp_min\": 75, \"temp_max\": 85, \"humidity\": 65}",
|
||||
"parametersPlaceholder": "{\"temp_min\": 75, \"temp_max\": 85, \"humidity\": 65}",
|
||||
"thresholdsJson": "Thresholds (JSON)",
|
||||
"thresholdsTooltip": "Threshold values: {\"critical\": 90, \"warning\": 70, \"acceptable\": 50}",
|
||||
"thresholdsPlaceholder": "{\"critical\": 90, \"warning\": 70, \"acceptable\": 50}",
|
||||
"scoringCriteriaJson": "Scoring Criteria (JSON)",
|
||||
"scoringCriteriaTooltip": "Custom scoring criteria: {\"appearance\": 30, \"texture\": 30, \"taste\": 40}",
|
||||
"scoringCriteriaPlaceholder": "{\"appearance\": 30, \"texture\": 30, \"taste\": 40}",
|
||||
"responsibleRole": "Responsible Role/Person",
|
||||
"responsibleRolePlaceholder": "E.g., Production Manager, Baker",
|
||||
"requiredEquipment": "Required Equipment/Tools",
|
||||
"requiredEquipmentPlaceholder": "E.g., Thermometer, scale, timer",
|
||||
"specificConditions": "Specific Conditions or Notes",
|
||||
"specificConditionsPlaceholder": "E.g., Only applicable on humid days, check 30 min after baking...",
|
||||
"passThresholdPercent": "Pass Threshold (%)",
|
||||
"frequencyDays": "Frequency (days)",
|
||||
"frequencyPlaceholder": "Leave empty for batch-based",
|
||||
"requiredCheck": "Required Check",
|
||||
"activeTemplate": "Active Template",
|
||||
"requiresPhotoEvidence": "Requires Photo Evidence",
|
||||
"criticalControlPoint": "Critical Control Point (CCP)",
|
||||
"notifyOnFailure": "Notify on Failure",
|
||||
"templateDetailsTitle": "Template Details"
|
||||
}
|
||||
},
|
||||
"customerOrder": {
|
||||
|
||||
@@ -163,7 +163,49 @@
|
||||
"basicInformation": "Información Básica",
|
||||
"scoringConfiguration": "Configuración de Puntuación",
|
||||
"advancedOptions": "Opciones Avanzadas",
|
||||
"advancedOptionsDescription": "Campos opcionales para configuración completa de plantilla de calidad"
|
||||
"advancedOptionsDescription": "Campos opcionales para configuración completa de plantilla de calidad",
|
||||
"checkPointsConfiguration": "Configuración de Puntos de Control",
|
||||
"advancedConfiguration": "Configuración Avanzada (JSONB)",
|
||||
"responsibilityRequirements": "Responsabilidad y Requisitos",
|
||||
"controlSettings": "Configuración de Control"
|
||||
},
|
||||
"scoringMethods": {
|
||||
"scoringMethod": "Método de Puntuación",
|
||||
"weightedAverage": "Promedio Ponderado",
|
||||
"passFail": "Aprobar/Reprobar",
|
||||
"percentage": "Porcentaje",
|
||||
"pointsBased": "Basado en Puntos"
|
||||
},
|
||||
"advancedFields": {
|
||||
"checkPointsJsonArray": "Puntos de Control (Array JSON)",
|
||||
"checkPointsTooltip": "Array de puntos de control: [{\"name\": \"Control Visual\", \"description\": \"...\", \"weight\": 1.0}]",
|
||||
"checkPointsPlaceholder": "[{\"name\": \"Inspección Visual\", \"description\": \"Verificar apariencia\", \"expected_value\": \"Marrón dorado\", \"measurement_type\": \"visual\", \"is_critical\": false, \"weight\": 1.0}]",
|
||||
"acceptanceCriteria": "Criterios de Aceptación",
|
||||
"acceptanceCriteriaPlaceholder": "Ej: Color dorado uniforme, textura esponjosa, sin quemaduras...",
|
||||
"parametersJson": "Parámetros (JSON)",
|
||||
"parametersTooltip": "Parámetros de plantilla: {\"temp_min\": 75, \"temp_max\": 85, \"humidity\": 65}",
|
||||
"parametersPlaceholder": "{\"temp_min\": 75, \"temp_max\": 85, \"humidity\": 65}",
|
||||
"thresholdsJson": "Umbrales (JSON)",
|
||||
"thresholdsTooltip": "Valores de umbral: {\"critical\": 90, \"warning\": 70, \"acceptable\": 50}",
|
||||
"thresholdsPlaceholder": "{\"critical\": 90, \"warning\": 70, \"acceptable\": 50}",
|
||||
"scoringCriteriaJson": "Criterios de Puntuación (JSON)",
|
||||
"scoringCriteriaTooltip": "Criterios de puntuación personalizados: {\"appearance\": 30, \"texture\": 30, \"taste\": 40}",
|
||||
"scoringCriteriaPlaceholder": "{\"appearance\": 30, \"texture\": 30, \"taste\": 40}",
|
||||
"responsibleRole": "Rol/Persona Responsable",
|
||||
"responsibleRolePlaceholder": "Ej: Gerente de Producción, Panadero",
|
||||
"requiredEquipment": "Equipos/Herramientas Requeridas",
|
||||
"requiredEquipmentPlaceholder": "Ej: Termómetro, báscula, temporizador",
|
||||
"specificConditions": "Condiciones o Notas Específicas",
|
||||
"specificConditionsPlaceholder": "Ej: Solo aplicable en días húmedos, verificar 30 min después de hornear...",
|
||||
"passThresholdPercent": "Umbral de Aprobación (%)",
|
||||
"frequencyDays": "Frecuencia (días)",
|
||||
"frequencyPlaceholder": "Dejar vacío para basado en lotes",
|
||||
"requiredCheck": "Verificación Requerida",
|
||||
"activeTemplate": "Plantilla Activa",
|
||||
"requiresPhotoEvidence": "Requiere Evidencia Fotográfica",
|
||||
"criticalControlPoint": "Punto Crítico de Control (PCC)",
|
||||
"notifyOnFailure": "Notificar en Falla",
|
||||
"templateDetailsTitle": "Detalles de Plantilla"
|
||||
}
|
||||
},
|
||||
"customerOrder": {
|
||||
|
||||
@@ -163,7 +163,49 @@
|
||||
"basicInformation": "Oinarrizko Informazioa",
|
||||
"scoringConfiguration": "Puntuazio Konfigurazioa",
|
||||
"advancedOptions": "Aukera Aurreratuak",
|
||||
"advancedOptionsDescription": "Kalitate txantiloi konfigurazio osoa egiteko eremu aukerazkoak"
|
||||
"advancedOptionsDescription": "Kalitate txantiloi konfigurazio osoa egiteko eremu aukerazkoak",
|
||||
"checkPointsConfiguration": "Kontrol Puntuen Konfigurazioa",
|
||||
"advancedConfiguration": "Konfigurazio Aurreratua (JSONB)",
|
||||
"responsibilityRequirements": "Erantzukizuna eta Eskakizunak",
|
||||
"controlSettings": "Kontrol Ezarpenak"
|
||||
},
|
||||
"scoringMethods": {
|
||||
"scoringMethod": "Puntuazio Metodoa",
|
||||
"weightedAverage": "Batez Besteko Haztatua",
|
||||
"passFail": "Gainditu/Huts egin",
|
||||
"percentage": "Ehunekoa",
|
||||
"pointsBased": "Puntuetan Oinarrituta"
|
||||
},
|
||||
"advancedFields": {
|
||||
"checkPointsJsonArray": "Kontrol Puntuak (JSON Array)",
|
||||
"checkPointsTooltip": "Kontrol puntuen array-a: [{\"name\": \"Ikusizko Kontrola\", \"description\": \"...\", \"weight\": 1.0}]",
|
||||
"checkPointsPlaceholder": "[{\"name\": \"Ikusizko Ikuskatzea\", \"description\": \"Itxura egiaztatu\", \"expected_value\": \"Urre marroia\", \"measurement_type\": \"visual\", \"is_critical\": false, \"weight\": 1.0}]",
|
||||
"acceptanceCriteria": "Onarpenerako Irizpideak",
|
||||
"acceptanceCriteriaPlaceholder": "Adib: Kolore urre uniformea, ehundura puzgatua, erreadurak gabe...",
|
||||
"parametersJson": "Parametroak (JSON)",
|
||||
"parametersTooltip": "Txantiloiaren parametroak: {\"temp_min\": 75, \"temp_max\": 85, \"humidity\": 65}",
|
||||
"parametersPlaceholder": "{\"temp_min\": 75, \"temp_max\": 85, \"humidity\": 65}",
|
||||
"thresholdsJson": "Atalaseak (JSON)",
|
||||
"thresholdsTooltip": "Atalase balioak: {\"critical\": 90, \"warning\": 70, \"acceptable\": 50}",
|
||||
"thresholdsPlaceholder": "{\"critical\": 90, \"warning\": 70, \"acceptable\": 50}",
|
||||
"scoringCriteriaJson": "Puntuazio Irizpideak (JSON)",
|
||||
"scoringCriteriaTooltip": "Puntuazio irizpide pertsonalizatuak: {\"appearance\": 30, \"texture\": 30, \"taste\": 40}",
|
||||
"scoringCriteriaPlaceholder": "{\"appearance\": 30, \"texture\": 30, \"taste\": 40}",
|
||||
"responsibleRole": "Arduradunaren Rola/Pertsona",
|
||||
"responsibleRolePlaceholder": "Adib: Ekoizpen Kudeatzailea, Okindegilea",
|
||||
"requiredEquipment": "Beharrezko Ekipamendua/Tresnak",
|
||||
"requiredEquipmentPlaceholder": "Adib: Termometroa, balantza, kronometroa",
|
||||
"specificConditions": "Baldintza Espezifikoak edo Oharrak",
|
||||
"specificConditionsPlaceholder": "Adib: Egun hezetan soilik aplikagarria, labean 30 minutu geroago egiaztatu...",
|
||||
"passThresholdPercent": "Gainditzeko Atalasea (%)",
|
||||
"frequencyDays": "Maiztasuna (egunak)",
|
||||
"frequencyPlaceholder": "Utzi hutsik lote oinarritua izateko",
|
||||
"requiredCheck": "Beharrezko Egiaztapena",
|
||||
"activeTemplate": "Txantiloi Aktiboa",
|
||||
"requiresPhotoEvidence": "Argazki Frogak Behar Ditu",
|
||||
"criticalControlPoint": "Kontrol Puntu Kritikoa (KPK)",
|
||||
"notifyOnFailure": "Jakinarazi Hutsegitean",
|
||||
"templateDetailsTitle": "Txantiloiaren Xehetasunak"
|
||||
}
|
||||
},
|
||||
"customerOrder": {
|
||||
|
||||
Reference in New Issue
Block a user