-
Notifications
You must be signed in to change notification settings - Fork 8.6k
DEV: full calendar v6 #33737
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
DEV: full calendar v6 #33737
Changes from all commits
b7f40b8
521b250
f3373c1
37fd1b9
ecac242
7bcebc7
1827b61
054e9d3
e16df96
b87b258
88a0283
fc95ebb
241ca64
7257cf5
1409be5
5ada292
5b91464
957ddde
05fc416
16a231e
bc8a914
a619725
24332b6
9f88dbd
9b69f11
62115ea
0ee0deb
cfc5a55
45d640b
8362c92
15afeaf
852e24b
6dcb0aa
e30e0d1
667c665
a41470d
c99ac9d
b416b6d
78fb890
1b1f65e
c6fed4d
1001f51
c26973f
ec3a14b
3a6071f
c0c2570
53e2204
5058561
2d38333
6fbcb3a
bb4117c
4d13b7f
6cce7dd
dd4306d
830e818
d1635f5
a3f9faa
bbaea2d
0535c11
b6159d0
feb5cda
ab7617d
c43c7b1
d033094
5c886a1
44b1592
2d50a55
8627df8
e6734a1
ba2531d
3f1c021
0c9430c
cfbd1bd
2794795
7219c30
3557402
893cad1
ffd3f9c
d7dd763
ab743d5
46b8391
3ec8041
6a16074
a9b8793
d0da3ff
5690b1b
29f1d06
cdc4165
fde22b9
e614be1
6d71fff
2e052ec
11193e1
c866bd2
bb9f7e1
03cba30
cfec3ee
7088666
0419dc2
99d225d
8a89ca2
a4bcd8a
44d467d
b5cd86a
0608f85
e50ea56
3910999
31ef143
484f443
da2afb0
ba959dc
a8124b4
2818653
d099742
54d4e02
b97632f
d03f5a0
5ec5caa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,5 @@ export { Calendar } from "@fullcalendar/core"; | |
export { default as DayGrid } from "@fullcalendar/daygrid"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this file allows to efficiently load the full calendar when needed |
||
export { default as TimeGrid } from "@fullcalendar/timegrid"; | ||
export { default as List } from "@fullcalendar/list"; | ||
export { default as RRULE } from "@fullcalendar/rrule"; | ||
export { default as MomentTimezone } from "@fullcalendar/moment-timezone"; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,12 +9,12 @@ def index | |
) | ||
|
||
# The detailed serializer is currently not used anywhere in the frontend, but available via API | ||
serializer = params[:include_details] == "true" ? EventSerializer : EventSummarySerializer | ||
serializer = params[:include_details] == "true" ? EventSerializer : BasicEventSerializer | ||
|
||
render json: | ||
ActiveModel::ArraySerializer.new( | ||
@events, | ||
each_serializer: serializer, | ||
each_serializer: BasicEventSerializer, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. always using the same serializer for lists, technically that could break stuff, but I didn't find anything There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this has potential to strip fields that our frontend isn't using, but customers are relying on externally (not sure, I didn't compare field-by-field yet). Context from Meta: /t/-/287566/14 |
||
scope: guardian, | ||
).as_json | ||
end | ||
|
@@ -124,6 +124,8 @@ def filtered_events_params | |
:limit, | ||
:before, | ||
:attending_user, | ||
:before, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we only had before, I added after to be able to have a range |
||
:after, | ||
) | ||
end | ||
end | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -59,40 +59,19 @@ def create_or_update_event_date | |
|
||
return if !starts_at_changed && !ends_at_changed | ||
|
||
event_dates.update_all(finished_at: Time.current) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this was fixing a bug introduced months ago which was causing recurring events to be marke as finished |
||
set_next_date | ||
end | ||
|
||
def set_next_date | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just a full refactoring of these methods |
||
next_dates = calculate_next_date | ||
return if !next_dates | ||
next_date_result = calculate_next_date | ||
|
||
date_args = { starts_at: next_dates[:starts_at], ends_at: next_dates[:ends_at] } | ||
if next_dates[:ends_at] && next_dates[:ends_at] < Time.current | ||
date_args[:finished_at] = next_dates[:ends_at] | ||
end | ||
|
||
existing_date = event_dates.find_by(starts_at: date_args[:starts_at]) | ||
|
||
if existing_date && existing_date.ends_at == date_args[:ends_at] && | ||
existing_date.finished_at == date_args[:finished_at] | ||
# exact same state in DB, this is a dupe call, return early | ||
return | ||
end | ||
|
||
if existing_date | ||
existing_date.update!(date_args) | ||
else | ||
event_dates.create!(date_args) | ||
end | ||
|
||
invitees.where.not(status: Invitee.statuses[:going]).update_all(status: nil, notified: false) | ||
|
||
if !next_dates[:rescheduled] | ||
notify_invitees! | ||
notify_missing_invitees! | ||
end | ||
return event_dates.update_all(finished_at: Time.current) if next_date_result.nil? | ||
|
||
starts_at, ends_at = next_date_result | ||
finish_previous_event_dates(starts_at) if dates_changed? | ||
upsert_event_date(starts_at, ends_at) | ||
reset_invitee_notifications | ||
notify_if_new_event | ||
publish_update! | ||
end | ||
|
||
|
@@ -400,27 +379,71 @@ def chat_channel_sync | |
end | ||
|
||
def calculate_next_date | ||
if self.recurrence.blank? || original_starts_at > Time.current | ||
return { starts_at: original_starts_at, ends_at: original_ends_at, rescheduled: false } | ||
if recurrence.blank? || original_starts_at > Time.current | ||
return original_starts_at, original_ends_at | ||
end | ||
|
||
next_starts_at = | ||
RRuleGenerator.generate( | ||
starts_at: original_starts_at.in_time_zone(timezone), | ||
timezone:, | ||
recurrence:, | ||
recurrence_until:, | ||
).first | ||
return unless next_starts_at | ||
|
||
if original_ends_at | ||
difference = original_ends_at - original_starts_at | ||
next_ends_at = next_starts_at + difference.seconds | ||
next_starts_at = calculate_next_recurring_date | ||
return nil unless next_starts_at | ||
|
||
next_ends_at = original_ends_at ? next_starts_at + event_duration : nil | ||
[next_starts_at, next_ends_at] | ||
end | ||
|
||
private | ||
|
||
def dates_changed? | ||
saved_change_to_original_starts_at || saved_change_to_original_ends_at | ||
end | ||
|
||
def finish_previous_event_dates(current_starts_at) | ||
existing_date = event_dates.find_by(starts_at: current_starts_at) | ||
event_dates | ||
.where.not(id: existing_date&.id) | ||
.where(finished_at: nil) | ||
.update_all(finished_at: Time.current) | ||
end | ||
|
||
def upsert_event_date(starts_at, ends_at) | ||
finished_at = ends_at && ends_at < Time.current ? ends_at : nil | ||
|
||
existing_date = event_dates.find_by(starts_at:) | ||
|
||
if existing_date | ||
# Only update if something actually changed | ||
unless existing_date.ends_at == ends_at && existing_date.finished_at == finished_at | ||
existing_date.update!(ends_at:, finished_at:) | ||
end | ||
else | ||
next_ends_at = nil | ||
event_dates.create!(starts_at:, ends_at:, finished_at:) | ||
end | ||
end | ||
|
||
def reset_invitee_notifications | ||
invitees.where.not(status: Invitee.statuses[:going]).update_all(status: nil, notified: false) | ||
end | ||
|
||
def notify_if_new_event | ||
is_generating_future_recurrence = recurrence.present? && original_starts_at <= Time.current | ||
|
||
unless is_generating_future_recurrence | ||
notify_invitees! | ||
notify_missing_invitees! | ||
end | ||
end | ||
|
||
def calculate_next_recurring_date | ||
RRuleGenerator.generate( | ||
starts_at: original_starts_at.in_time_zone(timezone), | ||
timezone: timezone, | ||
recurrence: recurrence, | ||
recurrence_until: recurrence_until, | ||
dtstart: original_starts_at.in_time_zone(timezone), | ||
).first | ||
end | ||
|
||
{ starts_at: next_starts_at, ends_at: next_ends_at, rescheduled: true } | ||
def event_duration | ||
original_ends_at - original_starts_at | ||
end | ||
end | ||
end | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just using the same rrule name everywhere