diff --git a/app/javascript/components/ComplexDatationInput/components/ComplexDatationInput.jsx b/app/javascript/components/ComplexDatationInput/components/ComplexDatationInput.jsx index b5a94d6bc..686ab0774 100644 --- a/app/javascript/components/ComplexDatationInput/components/ComplexDatationInput.jsx +++ b/app/javascript/components/ComplexDatationInput/components/ComplexDatationInput.jsx @@ -16,7 +16,8 @@ const ComplexDatationInput = (props) => { choiceSets: choiceSetsProps, selectedFormat: selectedFormatProps, fieldUuid, - componentPolicies + componentPolicies, + errors } = props const [choiceSets, setChoiceSets] = useState(choiceSetsProps) @@ -110,9 +111,12 @@ const ComplexDatationInput = (props) => { setToState(to); }, [granularity]) - let dateValid = isCurrentFormatValid(); - let errorStl = dateValid ? {} : {border: "2px solid #f00"}; - let errorMsg = dateValid ? "" : "Invalid value"; + let fromDateValid = isCurrentFormatValid('from'); + let toDateValid = isCurrentFormatValid('to'); + let errorStl = { + "from": fromDateValid ? {} : {border: "2px solid #f00"}, + "to": toDateValid ? {} : {border: "2px solid #f00"} + }; let fmt = getFieldOptions().format; function _handleChangeBC(input) { @@ -240,17 +244,18 @@ const ComplexDatationInput = (props) => { }); } - function getCurrentFormat() { + function getCurrentFormat(input) { let d = getData(); let f = getFieldOptions().format; return f.split('').map(function (k) { - return d['from'][k] ? k : d['to'][k] ? k : ''; + return d[input][k] ? k : ''; }).join('') } - function isCurrentFormatValid() { - let current = getCurrentFormat(); + function isCurrentFormatValid(input) { + let current = getCurrentFormat(input); if (current === '' && !isRequired) return true; // allow empty value if field is not required + if (current === '' && isRequired && getCurrentFormat(input === "from" ? "to" : "from") !== '') return true; let allowed = getAllowedFormats(); return allowed.indexOf(current) > -1; } @@ -274,13 +279,13 @@ const ComplexDatationInput = (props) => { ) : null} {fmt.includes('D') ? ( - ) : null } {fmt.includes('M') ? ( - ) : null } {fmt.includes('Y') ? ( - ) : null } {fmt.includes('h') ? ( - ) : null } {fmt.includes('m') ? ( - ) : null } {fmt.includes('s') ? ( - ) : null @@ -353,21 +358,21 @@ const ComplexDatationInput = (props) => { ) } - if (!fromState || !toState) return "" + if (!fromState || !toState) return "" return (
{renderAllowedFormatsSelector()}
{selectedFormat === 'date_time' && ( -
-
{renderDateTimeInput('from')}
-
{renderDateTimeInput('to')}
- {errorMsg} -
+
+
{renderDateTimeInput('from', input)}
+
{renderDateTimeInput('to', input)}
+
{errors?.filter(e => e.field === input.split("#item_")[1].split("_json")[0])?.map(e => e.message)?.join(',')}
+
)} - {selectedFormat === 'datation_choice' && ( - {
{errorMsg}
-
diff --git a/app/javascript/components/DateTimeInput/components/DateTimeInput.jsx b/app/javascript/components/DateTimeInput/components/DateTimeInput.jsx index e273c268d..e122d1e3c 100644 --- a/app/javascript/components/DateTimeInput/components/DateTimeInput.jsx +++ b/app/javascript/components/DateTimeInput/components/DateTimeInput.jsx @@ -10,7 +10,8 @@ const DateTimeInput = (props) => { const { input, allowBC, - preventNegativeInput + preventNegativeInput, + errors } = props const [state, setState] = useState(false) @@ -39,7 +40,6 @@ const DateTimeInput = (props) => { let dateValid = isCurrentFormatValid(); let errorStl = dateValid ? {} : {border: "2px solid #f00"}; - let errorMsg = dateValid ? "" : "Invalid value"; let fmt = getFieldOptions().format; function _handleChangeDay(e) { @@ -218,7 +218,8 @@ const DateTimeInput = (props) => { ) : null } {fmt.includes('Y') ? ( - ) : null } @@ -238,7 +239,7 @@ const DateTimeInput = (props) => { ) : null }
- {errorMsg} +
{errors?.filter(e => e.field === input.split("#item_")[1].split("_json")[0])?.map(e => e.message)?.join(',')}
); }; diff --git a/app/models/field/complex_datation.rb b/app/models/field/complex_datation.rb index 495e1c98c..49ac12685 100644 --- a/app/models/field/complex_datation.rb +++ b/app/models/field/complex_datation.rb @@ -170,7 +170,13 @@ def edit_props(item) componentPolicies: { modal: "super-editor" + }, + errors: item[:item].errors.map do |error| + { + message: error.message, + field: error.attribute } + end } end @@ -276,18 +282,29 @@ class ComplexDatationValidator < ActiveModel::Validator def validate(record) attrib = Array.wrap(options[:attributes]).first value = record.public_send(attrib) + field = Field.find_by(uuid: attrib) return if value.blank? - return if value['selected_format'] != "date_time" + to_value_empty = value['to'].keys.reject{|k| k=="BC"}.all? { |key| value['to'][key].blank? || value['to'][key].nil? } + from_value_empty = value['from'].keys.reject{|k| k=="BC"}.all? { |key| value['from'][key].blank? || value['from'][key].nil? } + return if to_value_empty && from_value_empty && !field.required - from_date_is_positive = value['from'].compact.except("BC").all? { |_, v| v.to_i >= 0 } + if to_value_empty && from_value_empty && field.required + record.errors.add(attrib, I18n.t('activerecord.errors.models.item.attributes.base.cant_be_blank')) + return + end + from_date_is_positive = value['from'].compact.except("BC").all? { |_, v| v.to_i >= 0 } to_date_is_positive = value['to'].compact.except("BC").all? { |_, v| v.to_i >= 0 } - return if to_date_is_positive && from_date_is_positive + allowed_formats = Field::ComplexDatation::FORMATS.select{|f| field.format.include?(f) || field.format == f} + + current_from_format = field.format.chars.map {|char| value['from'][char].blank? || value['from'][char].nil? ? nil : char}.compact.join + current_to_format = field.format.chars.map {|char| value['to'][char].blank? || value['to'][char].nil? ? nil : char}.compact.join - record.errors.add(:base, :negative_dates) + record.errors.add(attrib, I18n.t('activerecord.errors.models.item.attributes.base.wrong_format', field_format: allowed_formats)) unless (allowed_formats.include?(current_from_format) || from_value_empty) && (allowed_formats.include?(current_to_format) || to_value_empty) + record.errors.add(attrib, :negative_dates) if !to_date_is_positive || !from_date_is_positive end end end diff --git a/app/models/field/date_time.rb b/app/models/field/date_time.rb index 38f9541fa..072e50234 100644 --- a/app/models/field/date_time.rb +++ b/app/models/field/date_time.rb @@ -159,6 +159,17 @@ def sql_type "JSON" end + def edit_props(item) + { + errors: item[:item].errors.map do |error| + { + message: error.message, + field: error.attribute + } + end + } + end + private def transform_value(v) @@ -182,4 +193,31 @@ def coerce_to_array(values) array << values[key] end.compact end + + def build_validators + [DateTimeValidator] + end + + class DateTimeValidator < ActiveModel::Validator + def validate(record) + attrib = Array.wrap(options[:attributes]).first + value = record.public_send(attrib) + field = Field.find_by(uuid: attrib) + + return if value.blank? + return if value.is_a?(Hash) && value.has_key?("raw_value") + return if value.keys.all? { |key| value[key].blank? || value[key].nil? } && !field.required + + if value.keys.all? { |key| value[key].blank? || value[key].nil? } && field.required + record.errors.add(attrib, I18n.t('activerecord.errors.models.item.attributes.base.cant_be_blank')) + return + end + + allowed_formats = Field::DateTime::FORMATS.select{|f| field.format.include?(f) || field.format == f} + current_format = field.format.chars.map {|char| value[char].blank? || value[char].nil? ? nil : char}.compact.join + + record.errors.add(attrib, I18n.t('activerecord.errors.models.item.attributes.base.wrong_format', field_format: allowed_formats)) unless allowed_formats.include?(current_format) + end + end end + diff --git a/config/locales/app/en.yml b/config/locales/app/en.yml index bcf631382..4f61dde8a 100644 --- a/config/locales/app/en.yml +++ b/config/locales/app/en.yml @@ -65,7 +65,9 @@ en: item: attributes: base: + cant_be_blank: "Must be present" negative_dates: "Negative dates must be entered with the option before Jesus Christ (if activated)" + wrong_format: "Do not respect the formats %{field_format}" field/choice_set: attributes: choice_set_id: diff --git a/config/locales/app/fr.yml b/config/locales/app/fr.yml index c4fa10b07..124c66d8e 100644 --- a/config/locales/app/fr.yml +++ b/config/locales/app/fr.yml @@ -67,7 +67,9 @@ fr: item: attributes: base: + cant_be_blank: "Doit être rempli(e)" negative_dates: "Les dates négatives doivent être saisies avec l'option avant Jesus Christ (si activée)" + wrong_format: "Ne respecte pas les formats %{field_format}" field/choice_set: attributes: choice_set_id: