5 Pastor of the Day Scheduling Shared by Jeff Richmond, The Well Community Church 9 months ago 15.0 Operations Beginner Description Each weekday we schedule one pastor to be on-call as the Pastor of the Day (POD) so that we always have a pastor available when needed. As a part of our ongoing effort to replace various Google products with Rock, we recently moved our POD schedules over to the group scheduling system in Rock instead. This recipe will walk you through setting up the following features: A POD group for managing and scheduling your PODs A widget on the Rock home page that displays today's POD, complete with phone extension, email address and optionally a link to start a new direct message in Slack An upcoming POD page that shows the scheduled pastors for the next 14 days, as well as all scheduled dates for each pastor for the next 12 months A schedule preferences page for pastors (and staff) to manage their schedule from their My Settings area in Rock A Lava webhook that will serve as an iCal feed for the POD schedule If you'd prefer to not use the the group scheduling feature or if my solution just isn't quite what you were looking for, be sure to check out the Pastor On Call Block recipe by Morgan Woods. Morgan's recipe uses content channels instead of group scheduling. (Please let me know if there are any other similar recipes I may have missed) Prerequisites This recipe uses some of our own specific Rock customizations that may or may not match your situation. You may have to either make some extra changes to your Rock instance or modify the code in this recipe to work with your situation. Staff Person Tag We identify staff with an person tag: Name: Staff Scope: Organizational Entity Type: Person Staff-Related Person Attributes Staff Photo We keep a separate staff photo so everyone has a professional photo that's consistent with the rest of staff, rather than relying on the main profile photo Key: StaffPhoto Field Type: Image Phone Extension Key: StaffPhoneExtension Field Type: Text Slack User ID If your organization uses Slack for communication, this recipe can include a link for starting a new DM directly in Slack. You'll just need to store each staff member's Slack User ID. You'll also need to make a note of your organization's Slack Team ID. Key: SlackUserID Field Type: Text How-To Core POD Scheduling System Pastor of the Day Schedule Create a schedule of days that your pastors will be scheduled for. Name: Pastor of the Day Schedule: Set the schedule for your situation. Ours is weekly on Monday through Thursday from 9am to 5pm. Group Type You can either create a new group type or use an existing one. There are only a few options that must be set on the group type: General > Enable Location Schedules: Yes General > Location Types: Meeting Location Scheduling > Scheduling Enabled: Yes Pastor of the Day Group Create a new group using the group type specified above for keeping track of your POD pastors. Name: Pastor of the Day Meeting Details: Add a Group Location Location: Select the named location for your offices Type: Meeting Location Schedule(s): Select the schedule you created above Capacities: Set the capacities as needed. Ours are set to 1, 1, 1. Make a note of the ID of your new group for use in upcoming steps. Add your pastors and start scheduling Go ahead and add everyone who is eligible to be pastor of the day to this group. Once they have been added, you can go to the Group Scheduling page or just click the Group Scheduler button () on the group to start scheduling your pastors. Home Page Widget Add a new HTML Content block to your internal Rock home page. I recommend adding it to the top of the Sidebar 1 zone, but you can add it wherever you want. Edit the block properties and enable the Cache and Rock Entity Lava Commands. Edit the block content and add the following HTML/Lava. Replace the ID number on the first line with the ID of your POD group, and the Slack Team ID with your team ID. {%- assign podGroupID = 12345 -%} {%- assign slackTeamID = 'A0BCDE1FG' -%} //----------------------------------------------------------- {%- capture podHTML %} {%- cache key:'current-pod' tags:'internal-news' duration:'3600' -%} {%- assign dateKey = 'Now' | Date:'yyyyMMdd' -%} {%- assign pastorCount = 0 -%} {%- attendanceoccurrence where:'GroupId == {{ podGroupID }} && OccurrenceDateKey == "{{ dateKey }}"' disableattributeprefetch:'true' securetyenabled:'false' -%} {%- for occurrence in attendanceoccurrenceItems -%} {%- for attendee in occurrence.Attendees -%} {%- if attendee.ScheduledToAttend == true -%} {%- assign pastorCount = pastorCount | Plus:1 -%} {%- assign pastor = attendee.PersonAlias.Person -%} {%- assign phoneExt = pastor | Attribute:'StaffPhoneExtension' | Default:'' -%} {%- assign slackUserID = pastor | Attribute:'SlackUserID' | Default:'' -%} <div class="d-flex align-items-center"> <div class="d-none d-sm-block mr-2"> <a href="/person/{{ pastor.Id }}" title="View {{ pastor.NickName }}'s profile"> <img src="/GetAvatar.ashx?Style=icon&PhotoId={{ pastor | Attribute:'StaffPhoto','Id' }}&Gender={{ pastor.Gender }}&BackgroundColor=eceae8&ForegroundColor=c0bebc" alt="{{ pastor.FullName }}" style="max-width:100px;width:100%;border-radius:50%;display:inline-block;float:none;margin:5px auto;padding:2px;border:3px solid #06c;" /> </a> </div> <div class="text-left"> <a href="/person/{{ pastor.Id }}" title="View {{ pastor.NickName }}'s profile"> <strong>{{ pastor.FullName }}</strong> </a> <small class="text-muted d-block"> {%- if phoneExt != '' -%} <div class="d-flex"> <i class="fa fa-fw fa-phone mr-1" style="line-height:inherit"></i> <span class="flex-grow-1">x{{ phoneExt }}</span> </div> {%- endif -%} {%- if slackUserID != '' -%} <div class="d-flex"> <i class="fab fa-fw fa-slack mr-1" style="line-height:inherit"></i> <a href="slack://user?team={{ slackTeamID }}&id={{ slackUserID }}" target="_blank">Send Slack DM</a> </div> {%- endif -%} <div class="d-flex"> <i class="fa fa-fw fa-envelope mr-1" style="line-height:inherit"></i> <a class="js-copy-clipboard" title="Copy {{ pastor.NickName }}'s email address to your clipboard" data-clipboard-text="{{ pastor.Email }}" style="cursor:pointer">Copy Email</a> </div> </small> </div> </div> {%- endif -%} {%- endfor -%} {%- endfor -%} {%- if pastorCount == 0 -%} <div class="alert alert-info mb-0">No one is scheduled as POD today.</div> {%- endif -%} {%- endattendanceoccurrence -%} {%- endcache -%} {% endcapture -%} {%- capture footerHTML -%} <small><a class="btn btn-xs btn-link btn-icon" href="/staff/pod"><i class="fa fa-calendar-alt"></i> <span class="text">POD Schedule</span></a></small> {%- assign isPastor = CurrentPerson | Group:podGroupID | Size | AsBoolean -%} {%- if isPastor == true -%} <small><a class="btn btn-xs btn-link btn-icon" href="/my/schedules"><i class="fa fa-edit"></i> <span class="text">My Availability</span></a></small> {%- endif -%} {%- endcapture -%} {[ panel type:'block' title:'Pastor of the Day' footer:'{{ footerHTML }}' ]} {{ podHTML }} {[ endpanel ]} <script src="/scripts/clipboard.js/clipboard.min.js?v=637511048140000000" type="text/javascript"></script> <script> $('.js-copy-clipboard').tooltip( { trigger: 'click', placement: 'bottom' }); function setTooltip(btn, message) { btn.tooltip('hide') .attr('data-original-title', message) .tooltip('show'); } function hideTooltip(btn) { setTimeout(function() { btn.tooltip('hide'); }, 2000); } var clipboard = new ClipboardJS('.js-copy-clipboard'); clipboard.on('success', function(e) { var btn = $(e.trigger); setTooltip(btn, 'Copied!'); hideTooltip(btn); }); </script> <style> .pod .panel-body { padding: 6px 18px; } .pod .panel-footer { padding: 5px 10px; } </style> Upcoming PODs Page Create a new page: Page Title: Upcoming PODs Site: Rock RMS Layout: Full Width Icon CSS Class: fas fa-bible Page Routes: staff/pod Add a new HTML Content block to the page's Main zone. Edit the block properties and enable the Rock Entity Lava Command. Edit the block content and add the following HTML/Lava. Replace the ID number on the first line with the ID of your POD group. {%- assign podGroupID = 12345 -%} //----------------------------------------------------------- {%- assign today = 'Now' | Date:'MM/dd/yyyy' | AsDateTime -%} {%- assign minDateKey = today | Date:'yyyyMMdd' -%} {%- assign maxDateKey = today | DateAdd:13,'d' | Date:'yyyyMMdd' -%} {%- assign minSundayDate = today | SundayDate | AsDateTime -%} {%- if today < minSundayDate %}{% assign minSundayDate = minSundayDate | DateAdd:-7,'d' %}{% endif -%} {%- attendanceoccurrence where:'GroupId == {{ podGroupID }} && OccurrenceDateKey >= "{{ minDateKey }}" && OccurrenceDateKey <= "{{ maxDateKey }}"' disableattributeprefetch:'true' securityenabled:'false' -%} {%- assign maxOccurDate = attendanceoccurrenceItems | OrderBy:'OccurrenceDate desc' | First | Property:'OccurrenceDate' -%} {%- assign maxSaturdayDate = maxOccurDate | SundayDate | DateAdd:-1,'d' | AsDateTime -%} {%- if maxOccurDate > maxSaturdayDate %}{% assign maxSaturdayDate = maxSaturdayDate | DateAdd:7,'d' %}{% endif -%} {%- if maxSaturdayDate == null %}{% assign maxSaturdayDate = minSundayDate | DateAdd:13,'d' %}{% endif -%} {%- assign dayCount = minSundayDate | DateDiff:maxSaturdayDate,'d' -%} {%- capture podHTML %} <div class="clearfix mb-3"><div class="pull-right"><small><a class="btn btn-xs btn-default" href="{{ 'Global' | Attribute:'PublicApplicationRoot' }}webhooks/lava.ashx/ical/pod"><i class="fa fa-calendar-check"></i> <span class="text">iCal Feed</span></a></small></div></div> <table class="calendar-view month-layout table-responsive"> <thead> <tr> <th scope="col" class="cell">Sunday</th> <th scope="col" class="cell">Monday</th> <th scope="col" class="cell">Tuesday</th> <th scope="col" class="cell">Wednesday</th> <th scope="col" class="cell">Thursday</th> <th scope="col" class="cell">Friday</th> <th scope="col" class="cell">Saturday</th> </tr> </thead> <tbody> {%- assign prevMonth = '' -%} {%- for i in (0..dayCount) -%} {%- assign date = minSundayDate | DateAdd:i,'d' -%} {%- assign dateKey = date | Date:'yyyyMMdd' -%} {%- assign weekday = date | Date:'dddd' -%} {%- assign month = date | Date:'MMMM' -%} {%- assign occurrences = attendanceoccurrenceItems | Where:'OccurrenceDate',date -%} {%- if weekday == 'Sunday' -%} <tr class="week"> {%- endif -%} <td class="cell day{% if date == today %} today{% endif %}"> {%- if month != prevMonth -%} {%- assign prevMonth = month -%} <div class="daynum">{{ date | Date:'MMMM d' }}</div> {%- else -%} <div class="daynum">{{ date | Date:'d' }}</div> {%- endif -%} <div class="pastors"> {%- for occurrence in attendanceoccurrenceItems -%} {%- if occurrence.OccurrenceDateKey == dateKey -%} {%- for attendee in occurrence.Attendees -%} {%- if attendee.ScheduledToAttend == true -%} {%- assign pastor = attendee.PersonAlias.Person -%} {%- assign phoneExt = pastor | Attribute:'StaffPhoneExtension' | Default:'' -%} {%- assign slackUserID = pastor | Attribute:'SlackUserID' | Default:'' -%} {%- assign photoURL = pastor | Attribute:'StaffPhoto','RawValue' | ImageUrl:'' -%} {%- capture photoHTML -%} <a href="/person/{{ pastor.Id }}" title="View {{ pastor.NickName }}'s profile"> <img src="/GetAvatar.ashx?Style=icon&PhotoId={{ pastor | Attribute:'StaffPhoto','Id' }}&Gender={{ pastor.Gender }}&BackgroundColor=eceae8&ForegroundColor=c0bebc" alt="{{ pastor.FullName }}" style="max-width:100px;width:100%;border-radius:50%;display:inline-block;float:none;margin:5px auto;padding:2px;border:3px solid #06c;" /> </a> {%- endcapture -%} <div class="d-lg-flex align-items-center"> <div class="d-none d-sm-block mr-2">{{ photoHTML }}</div> <div class="text-left"> <a href="/person/{{ pastor.Id }}" title="View {{ pastor.NickName }}'s profile"> <strong>{{ pastor.FullName }}</strong> </a> <small class="text-muted d-block"> {%- if phoneExt != '' -%} <div class="d-flex"> <i class="fa fa-fw fa-phone mr-1" style="line-height:inherit"></i> <span class="flex-grow-1">x{{ phoneExt }}</span> </div> {%- endif -%} {%- if slackUserID != '' -%} <div class="d-flex"> <i class="fab fa-fw fa-slack mr-1" style="line-height:inherit"></i> <a href="slack://user?team=T0JDKG0RM&id={{ slackUserID }}" target="_blank">Send Slack DM</a> </div> {%- endif -%} <div class="d-flex"> <i class="fa fa-fw fa-envelope mr-1" style="line-height:inherit"></i> <a class="js-copy-clipboard" title="Copy {{ pastor.NickName }}'s email address to your clipboard" data-clipboard-text="{{ pastor.Email }}" style="cursor:pointer">Copy Email</a> </div> </small> </div> </div> {%- endif -%} {%- endfor -%} {%- endif -%} {%- endfor -%} </div> </td> {%- if weekday == 'Saturday' -%} </tr> {%- endif -%} {%- endfor -%} </tbody> </table> {% endcapture -%} {%- endattendanceoccurrence -%} {[ panel title:'Next 14 Days' ]} {{ podHTML }} {[ endpanel ]} <script src="/scripts/clipboard.js/clipboard.min.js?v=637511048140000000" type="text/javascript"></script> <script> $('.js-copy-clipboard').tooltip( { trigger: 'click', placement: 'bottom' }); function setTooltip(btn, message) { btn.tooltip('hide') .attr('data-original-title', message) .tooltip('show'); } function hideTooltip(btn) { setTimeout(function() { btn.tooltip('hide'); }, 2000); } var clipboard = new ClipboardJS('.js-copy-clipboard'); clipboard.on('success', function(e) { var btn = $(e.trigger); setTooltip(btn, 'Copied!'); hideTooltip(btn); }); </script> <style> .calendar-view th { padding: 5px 10px; border: 1px solid #ccc; text-align: center; background: #eee; } .calendar-view .daynum { padding: 3px 5px; text-align: right; font-size: 20px; background-color: #f6f6f6; } .calendar-view .today .daynum { background-color: #cfdbeb; } .calendar-view .pastors { padding: 5px 10px; min-height: 60px; } .calendar-view .week .cell { width: 14.2%; min-height: 200px; border: 1px solid #ccc; padding: 0; vertical-align: top; } .calendar-view .cell.today .indicator { background-color: #cfdbeb; color: #333; } </style> {[ panel title:'Next 12 Months' ]} <div class="row d-flex flex-wrap align-items-stretch"> {%- assign minDateKey = today | Date:'yyyyMMdd' -%} {%- assign maxDateKey = today | DateAdd:12,'M' | Date:'yyyyMMdd' -%} {%- assign pastors = podGroupID | GroupById | Property:'Members' | Select:'Person' | OrderBy:'LastName, NickName' -%} {%- attendanceoccurrence where:'GroupId == {{ podGroupID }} && OccurrenceDateKey >= "{{ minDateKey }}" && OccurrenceDateKey <= "{{ maxDateKey }}"' disableattributeprefetch:'true' securityenabled:'false' -%} {%- for pastor in pastors -%} {%- assign photoURL = pastor | Attribute:'StaffPhoto','RawValue' | ImageUrl:'' -%} {%- capture photoHTML -%} <a href="/person/{{ pastor.Id }}" title="View {{ pastor.NickName }}'s profile"> <img src="/GetAvatar.ashx?Style=icon&PhotoId={{ pastor | Attribute:'StaffPhoto','Id' }}&Gender={{ pastor.Gender }}&Radius=Circle&BackgroundColor=eceae8&ForegroundColor=c0bebc" alt="{{ pastor.FullName }}" style="width:36px;height:36px;border-radius:50%;display:inline-block;float:none;margin:5px auto;padding:2px;border:2px solid #06c;" /> </a> {%- endcapture -%} <div class="col-sm-6 col-md-4 col-lg-3 d-flex align-items-stretch"> <div class="panel panel-block w-100"> <div class="panel-heading"> <h4 class="panel-title">{{ photoHTML }} <a href="/person/{{ pastor.Id }}" title="View {{ pastor.NickName }}'s profile">{{ pastor.FullName | Escape }}</a></h4> </div> <div class="panel-body"> {%- assign occurrenceCount = 0 -%} {%- for occurrence in attendanceoccurrenceItems -%} {%- for attendee in occurrence.Attendees -%} {%- if attendee.PersonAliasId == pastor.PrimaryAliasId and attendee.ScheduledToAttend == true -%} {{ occurrence.OccurrenceDate | Date:'dddd, M/d/yyyy' }}<br> {%- assign occurrenceCount = occurrenceCount | Plus:1 -%} {%- break -%} {%- endif -%} {%- endfor -%} {%- endfor -%} {%- if occurrenceCount == 0 -%} <em class="text-muted">Not Currently Scheduled</em> {%- endif -%} </div> </div> </div> {%- endfor -%} {%- endattendanceoccurrence -%} </div> {[ endpanel ]} Schedule Preferences Page Create a new page under Internal Homepage > My Settings Page Title: Schedule Preferences Site: Rock RMS Layout: Full Width Icon CSS Class: fa fa-calendar-check Page Routes: my/schedules Add a new Group Schedule Toolbox block to the page's Main zone. If you haven't updated to Rock v16 yet, then use the one that ends with "v2". Edit the block settings and change the Future Week Date Range to Next 13 Weeks iCal Feed Create a new value under the Lava Webhooks defined type: Value: /ical/pod Description: Generates an iCal feed for the Pastor of the Day schedule Method: GET Enabled Lava Commands: Rock Entity Response Content Type: text/calendar Template: Replace the ID number on the first line with the ID of your POD group, and change all of the time zone information between BEGIN:VTIMEZONE and END:VTIMEZONE to match your location. {%- assign podGroupID = 12345 -%} //----------------------------------------------------------- {%- assign today = 'Now' | Date:'MM/dd/yyyy' | AsDateTime -%} {%- assign minDateKey = today | DateAdd:-1,'M' | Date:'yyyyMMdd' -%} {%- assign maxDateKey = today | DateAdd:12,'M' | Date:'yyyyMMdd' -%} BEGIN:VCALENDAR PRODID:-//{{ 'Global' | Attribute:'OrganizationName' }}//Rock POD Scheduler//EN VERSION:2.0 BEGIN:VTIMEZONE TZID:America/Los_Angeles X-LIC-LOCATION:America/Los_Angeles BEGIN:STANDARD DTSTART:20211107T020000 RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11 TZNAME:PST TZOFFSETFROM:-0700 TZOFFSETTO:-0800 END:STANDARD BEGIN:DAYLIGHT DTSTART:20220313T020000 RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3 TZNAME:PDT TZOFFSETFROM:-0800 TZOFFSETTO:-0700 END:DAYLIGHT END:VTIMEZONE {%- attendanceoccurrence where:'GroupId == {{ podGroupID }} && OccurrenceDateKey >= "{{ minDateKey }}" && OccurrenceDateKey <= "{{ maxDateKey }}"' -%} {%- assign occurrenceCount = 0 -%} {%- for occurrence in attendanceoccurrenceItems -%} {%- assign startDateTime = occurrence.OccurrenceDate | Date:'M/d/yyyy 00:00:00' | AsDateTime -%} {%- assign endDateTime = startDateTime | DateAdd:24,'h' %} {%- assign pastorCount = 0 -%} {%- assign pastorList = '' -%} {%- for pastor in occurrence.Attendees -%} {%- if pastor.ScheduledToAttend == true -%} {%- assign pastorCount = pastorCount | Plus:1 -%} {%- capture pastorList %}{{ pastorList }}{{ pastor.PersonAlias.Person.FullName }}{% if forloop.last == false %}\,{% endif %}{% endcapture -%} {%- endif -%} {%- endfor -%} {%- if pastorCount > 0 %} BEGIN:VEVENT DTSTAMP:{{ startDateTime | AsDateTimeUtc | Date:'yyyyMMddThhmmssZ' }} UID:POD{{ startDateTime | Date:'yyyyMMdd' }} DTSTART;VALUE=DATE:{{ startDateTime | Date:'yyyyMMdd' }} SUMMARY:POD: {{ pastorList }} END:VEVENT {%- endif -%} {%- endfor -%} {%- endattendanceoccurrence %} END:VCALENDAR All done! As soon as you have all of your pastors scheduled and confirmed, they should start showing up on the home page POD widget and the Upcoming PODs page. Follow Up Please don't hesitate to leave a comment below or hit me up on Rock Chat (@JeffRichmond) if you have questions or find any issues with this recipe. If you come up with better or more efficient ways of doing anything in this recipe, please let me know. Thanks! Change Log 2023-12-15 - Initial Version