|
2 | 2 |
|
3 | 3 | module Fields::Options |
4 | 4 | class DateField < FieldOptions |
| 5 | + attribute :start_from, :string, default: "unlimited" |
| 6 | + enum start_from: { |
| 7 | + unlimited: "unlimited", |
| 8 | + today: "today", |
| 9 | + date: "date", |
| 10 | + days_before_finish: "days_before_finish" |
| 11 | + }, _prefix: :start_from |
| 12 | + |
| 13 | + attribute :start_date, :date |
| 14 | + attribute :start_from_today_days_offset, :integer, default: 0 |
| 15 | + attribute :days_before_finish, :integer, default: 1 |
| 16 | + |
| 17 | + attribute :finish_to, :string, default: "unlimited" |
| 18 | + enum finish_to: { |
| 19 | + unlimited: "unlimited", |
| 20 | + today: "today", |
| 21 | + date: "date", |
| 22 | + days_since_start: "days_since_start" |
| 23 | + }, _prefix: :finish_to |
| 24 | + |
| 25 | + attribute :finish_date, :date |
| 26 | + attribute :finish_to_today_days_offset, :integer, default: 0 |
| 27 | + attribute :days_since_start, :integer, default: 1 |
| 28 | + |
| 29 | + validates :start_from, :finish_to, |
| 30 | + presence: true |
| 31 | + |
| 32 | + validates :start_date, |
| 33 | + presence: true, |
| 34 | + if: :start_from_date? |
| 35 | + |
| 36 | + validates :finish_date, |
| 37 | + presence: true, |
| 38 | + if: :finish_to_date? |
| 39 | + |
| 40 | + validates :days_before_finish, |
| 41 | + numericality: { |
| 42 | + only_integer: true, |
| 43 | + greater_than: 0 |
| 44 | + }, |
| 45 | + allow_blank: false, |
| 46 | + if: :start_from_days_before_finish? |
| 47 | + |
| 48 | + validates :days_since_start, |
| 49 | + numericality: { |
| 50 | + only_integer: true, |
| 51 | + greater_than: 0 |
| 52 | + }, |
| 53 | + allow_blank: false, |
| 54 | + if: :finish_to_days_since_start? |
| 55 | + |
| 56 | + validates :start_from_today_days_offset, :finish_to_today_days_offset, |
| 57 | + presence: true, |
| 58 | + numericality: { |
| 59 | + only_integer: true |
| 60 | + } |
| 61 | + |
| 62 | + validates :start_date, |
| 63 | + timeliness: { |
| 64 | + before: ->(r) { Time.zone.today + r.finish_to_today_days_offset.days }, |
| 65 | + type: :date |
| 66 | + }, |
| 67 | + allow_blank: false, |
| 68 | + if: [:start_from_date?, :finish_to_today?] |
| 69 | + |
| 70 | + validates :finish_date, |
| 71 | + timeliness: { |
| 72 | + after: -> { Time.zone.today + r.start_from_today_days_offset.days }, |
| 73 | + type: :date |
| 74 | + }, |
| 75 | + allow_blank: false, |
| 76 | + if: [:start_from_today?, :finish_to_date?] |
| 77 | + |
| 78 | + validates :finish_date, |
| 79 | + timeliness: { |
| 80 | + after: :start_date, |
| 81 | + type: :date |
| 82 | + }, |
| 83 | + allow_blank: false, |
| 84 | + if: [:start_from_date?, :finish_to_date?] |
| 85 | + |
| 86 | + validates :finish_to, |
| 87 | + exclusion: {in: %w[today]}, |
| 88 | + if: [:start_from_today?] |
| 89 | + |
| 90 | + validates :finish_to, |
| 91 | + exclusion: {in: %w[days_since_start]}, |
| 92 | + if: [:start_from_days_before_finish?] |
| 93 | + |
| 94 | + def interpret_to(model, field_name, accessibility, _options = {}) |
| 95 | + return unless accessibility == :read_and_write |
| 96 | + |
| 97 | + timeliness = {type: :date} |
| 98 | + |
| 99 | + if start_from_today? |
| 100 | + start_date_days_offset = self.start_from_today_days_offset.days |
| 101 | + timeliness[:on_or_after] = -> { Time.zone.today + start_date_days_offset } |
| 102 | + elsif start_from_date? |
| 103 | + timeliness[:on_or_after] = start_date |
| 104 | + elsif start_from_days_before_finish? |
| 105 | + days_before_finish = self.days_before_finish.days |
| 106 | + if finish_to_today? |
| 107 | + finish_date_days_offset = self.finish_to_today_days_offset.days |
| 108 | + timeliness[:on_or_after] = -> { |
| 109 | + Time.zone.today + finish_date_days_offset - days_before_finish |
| 110 | + } |
| 111 | + elsif finish_to_date? |
| 112 | + timeliness[:on_or_after] = finish_date - days_before_finish |
| 113 | + end |
| 114 | + end |
| 115 | + |
| 116 | + if finish_to_today? |
| 117 | + finish_date_days_offset = self.finish_to_today_date_offset.days |
| 118 | + timeliness[:on_or_before] = -> { Time.zone.today + finish_date_days_offset } |
| 119 | + elsif finish_to_date? |
| 120 | + timeliness[:on_or_before] = finish_date |
| 121 | + elsif finish_to_days_since_start? |
| 122 | + days_since_start = self.days_since_start.days |
| 123 | + if start_from_today? |
| 124 | + start_date_days_offset = self.start_from_today_days_offset.days |
| 125 | + timeliness[:on_or_before] = -> { |
| 126 | + Time.zone.today + start_date_days_offset + days_since_start |
| 127 | + } |
| 128 | + elsif start_from_date? |
| 129 | + timeliness[:on_or_before] = start_date + days_since_start |
| 130 | + end |
| 131 | + end |
| 132 | + |
| 133 | + model.validates field_name, |
| 134 | + timeliness: timeliness, |
| 135 | + allow_blank: true |
| 136 | + end |
5 | 137 | end |
6 | 138 | end |
0 commit comments