Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix date time and complex datation validations #20

Draft
wants to merge 10 commits into
base: development
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ const ComplexDatationInput = (props) => {
choiceSets: choiceSetsProps,
selectedFormat: selectedFormatProps,
fieldUuid,
componentPolicies
componentPolicies,
errors
} = props

const [choiceSets, setChoiceSets] = useState(choiceSetsProps)
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand All @@ -274,13 +279,13 @@ const ComplexDatationInput = (props) => {
</div>
) : null}
{fmt.includes('D') ? (
<input style={errorStl} type="number" min="0" max="31" className="input-2 form-control"
<input style={errorStl[input]} type="number" min="0" max="31" className="input-2 form-control"
value={input === 'from' ? fromState.D : toState.D}
onChange={_handleChangeDay(input)}/>
) : null
}
{fmt.includes('M') ? (
<select style={errorStl} className="form-control" value={input === 'from' ? fromState.M : toState.M}
<select style={errorStl[input]} className="form-control" value={input === 'from' ? fromState.M : toState.M}
onChange={_handleChangeMonth(input)}>
<option value=""></option>
<option value="1">
Expand Down Expand Up @@ -322,26 +327,26 @@ const ComplexDatationInput = (props) => {
</select>) : null
}
{fmt.includes('Y') ? (
<input style={errorStl} className="input-4 margin-right form-control"
<input style={errorStl[input]} className="input-4 margin-right form-control"
type="number" min="0"
value={input === 'from' ? fromState.Y : toState.Y}
onChange={_handleChangeYear(input)}/>
) : null
}
{fmt.includes('h') ? (
<input style={errorStl} min="0" max="23" type="number" className="input-2 form-control"
<input style={errorStl[input]} min="0" max="23" type="number" className="input-2 form-control"
value={input === 'from' ? fromState.h : toState.h}
onChange={_handleChangeHours(input)}/>
) : null
}
{fmt.includes('m') ? (
<input style={errorStl} min="0" max="59" type="number" className="input-2 form-control"
<input style={errorStl[input]} min="0" max="59" type="number" className="input-2 form-control"
value={input === 'from' ? fromState.m : toState.m}
onChange={_handleChangeMinutes(input)}/>
) : null
}
{fmt.includes('s') ? (
<input style={errorStl} min="0" max="59" type="number" className="input-2 form-control"
<input style={errorStl[input]} min="0" max="59" type="number" className="input-2 form-control"
value={input === 'from' ? fromState.s : toState.s}
onChange={_handleChangeSeconds(input)}/>
) : null
Expand All @@ -353,21 +358,21 @@ const ComplexDatationInput = (props) => {
)
}

if (!fromState || !toState) return ""
if (!fromState || !toState) return ""
return (
<div>
<div>{renderAllowedFormatsSelector()}</div>
{selectedFormat === 'date_time' && (
<div>
<div>{renderDateTimeInput('from')}</div>
<div>{renderDateTimeInput('to')}</div>
<span className="error helptext">{errorMsg}</span>
</div>
<div>
<div>{renderDateTimeInput('from', input)}</div>
<div>{renderDateTimeInput('to', input)}</div>
<div className="base-errors">{errors?.filter(e => e.field === input.split("#item_")[1].split("_json")[0])?.map(e => e.message)?.join(',')}</div>
</div>
)}
{selectedFormat === 'datation_choice' && (
<RenderChoiceSetList
choiceSets={choiceSets}
locales={locales}
{selectedFormat === 'datation_choice' && (
<RenderChoiceSetList
choiceSets={choiceSets}
locales={locales}
getData={getData}
setData={setData}
setChoiceData={setChoiceData}
Expand Down Expand Up @@ -777,7 +782,6 @@ const ModalForm = (props) => {
<div className="base-errors">
{errorMsg}
</div>

</div>
</div>
<div className="modal-footer">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ const DateTimeInput = (props) => {
const {
input,
allowBC,
preventNegativeInput
preventNegativeInput,
errors
} = props

const [state, setState] = useState(false)
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -218,7 +218,8 @@ const DateTimeInput = (props) => {
</select>) : null
}
{fmt.includes('Y') ? (
<input style={errorStl} type="number" min={preventNegativeInput ? "0" : "" } className="input-4 margin-right form-control" value={state.Y}
<input style={errorStl} type="number" min={preventNegativeInput ? "0" : ""}
className="input-4 margin-right form-control" value={state.Y}
onChange={_handleChangeYear}/>
) : null
}
Expand All @@ -238,7 +239,7 @@ const DateTimeInput = (props) => {
) : null
}
</div>
<span className="error helptext">{errorMsg}</span>
<div className="base-errors">{errors?.filter(e => e.field === input.split("#item_")[1].split("_json")[0])?.map(e => e.message)?.join(',')}</div>
</div>
);
};
Expand Down
25 changes: 21 additions & 4 deletions app/models/field/complex_datation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
38 changes: 38 additions & 0 deletions app/models/field/date_time.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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

2 changes: 2 additions & 0 deletions config/locales/app/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 2 additions & 0 deletions config/locales/app/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down