I'm looking for help coming up with the best strategy in Backdrop CMS for the following use case, which I could use to schedule sessions for Backdrop CMS Live if I get real ambitious OR I have some other ideas how I might use this as well.

I'd like to be able to create a bunch of time slots that could be available appointments OR session slots for a conference. Then, I'd like for a user to be able to create a node and select from the list of available time slots. The tricky part (for me) is figuring out how to limit it so that once a time slot or available appointment has been taken, it is no longer available in the future. 

I'm looking for existing strategies in Drupal 7 or Backdrop CMS for this kind of scenario OR ideas about how to best handle this in custom code (would love to be pointed at some existing code that does something similar). 

 

Accepted answer

I thought it would be fun to put together a small demonstration of this today using the references, views, date and rules modules, but no php coding.

In a nutshell, create a 'slot' content type that has fields for date, start time, end time, unique title & user reference. Create a node for each session slot, leaving the user references blank.

To control access I created a manager and a volunteer role and added some users with those roles. Mangers can add/edit/delete slots, volunteers can be assigned to slots, view a list of their appointments, assign themselves, open spots and remove assigned slots. 

 

Create a view with displays for listing volunteers. Create a view for listing slots, unassigned slots, assigned slots and slots assigned to a user.  Add links to allow user to assign and unassign from a slot.

 

 

Create a view for volunteer's profile tabs that shows their current assignments. Embed another view in the footer that shows available slots.  Add links to cancel and add assignments by linking to node/[nid]/assign and node/[nid]/unassign, which will be handled by a pair of rules.

Create rules to assign and unassign the current user from a given slot.

Here is the overview of the "assign" operation rule. Basically, when a volunteer visits a slot page with the word assign appended, we check that the slot is unassigned and fill the slot's user reference field with the current user.

It was fun figuring out how to do this without any programming, although that would be my preference instead of using rules.

There are lots of details as to how to configure the views and rules, but nothing very tricky. Things like handling access, menus, formatting, tokens, etc.

This is just a simple approach for use with limited sessions, e.g. conference sessions. For repeated daily slots such as for office appointments, separate slot and appointment types make more sense and add a little to the complexity with forward and backward references between 'slots' and 'appointments' but could still be built in a similar manner.

I hope this helps.

Most helpful answers

I set up another example, this time with two content types as you describe. 

No programming is required for this.  In fact, you don't even need the 'taken' field! :)

Just use a (reverse) reference view for the session nodes' time_slot field.

This is simply a view of all time_slots that do not have a session referencing them. This view has a 'reference' display instead of page or block so that it can be used as a lookup for select options on the session node add form.

Here is the view, with the important options set:

Here is the field def:

Here is the result when adding a second session after I had already taken Time Slot A:

Oops! I forgot to reverse the default sorting in the view! Easy fix!

Along with the simple filter, it's the reverse relationship in the view that makes this all work. The "reverse" option on relationships appears when you add one to a view:

The same technique could be used to display the "taken" status on a time_slot node's display without there actually being a field.

Alternatively, a rule or code could watch for changes to session time slot fields and use the reference to update a time_slot node's taken field if you must have one.  Rules and callbacks have access to old and new values when triggered by a field change. Use those to find the appropriate time slot and set or unset it's taken field.

I hope that applies to your approach.

Comments

ericfg's picture

Did something like this for a yearly conference a few years ago. Every time slot was a node and there was an entity reference field to the sessions that only allowed for one node to be connected (using views we would show/hide the 'add session' link based on the existence or not of that reference)

we also had locations (buildings and rooms) referenced to the time slots and profiles of the folks presenting referenced to the sessions.

this way we could use views to show daily schedules; schedules by room. There was a plan to have a view on each person's dashboard so they could mark what sessions they were interested in on the schedules and see their personal schedule

I might still have the code lying around if it's useful.

If the code is easy to find, I think it might be helpful to me. Ping me in Zulip or Twitter. Thanks.

ericfg's picture

will look around my dev archive later tonight

ericfg's picture

I'll ping in zulip -- I found the code, but when I said "a couple years ago" I apparently meant "almost 9 years ago" and it's all in Drupal 6. So it's likely useless to you but you're still welcome to poke at it if you want

I thought it would be fun to put together a small demonstration of this today using the references, views, date and rules modules, but no php coding.

In a nutshell, create a 'slot' content type that has fields for date, start time, end time, unique title & user reference. Create a node for each session slot, leaving the user references blank.

To control access I created a manager and a volunteer role and added some users with those roles. Mangers can add/edit/delete slots, volunteers can be assigned to slots, view a list of their appointments, assign themselves, open spots and remove assigned slots. 

 

Create a view with displays for listing volunteers. Create a view for listing slots, unassigned slots, assigned slots and slots assigned to a user.  Add links to allow user to assign and unassign from a slot.

 

 

Create a view for volunteer's profile tabs that shows their current assignments. Embed another view in the footer that shows available slots.  Add links to cancel and add assignments by linking to node/[nid]/assign and node/[nid]/unassign, which will be handled by a pair of rules.

Create rules to assign and unassign the current user from a given slot.

Here is the overview of the "assign" operation rule. Basically, when a volunteer visits a slot page with the word assign appended, we check that the slot is unassigned and fill the slot's user reference field with the current user.

It was fun figuring out how to do this without any programming, although that would be my preference instead of using rules.

There are lots of details as to how to configure the views and rules, but nothing very tricky. Things like handling access, menus, formatting, tokens, etc.

This is just a simple approach for use with limited sessions, e.g. conference sessions. For repeated daily slots such as for office appointments, separate slot and appointment types make more sense and add a little to the complexity with forward and backward references between 'slots' and 'appointments' but could still be built in a similar manner.

I hope this helps.

@apperceptions - Much thanks. You are a "rules" ninja!

I've used rules a fair amount, but I learned some really useful stuff from your example. I didn't know how to use paths that way. 

I walked through the entire example in BackdropCMS and everything worked. Views and Rules both worked pretty much exactly like Drupal 7. I would say the only thing that might have been different is the manner in which we place the blocks in BackdropCMS!

Your scenario is slightly different that what I had in mind, but your scenario contains all the important elements I need. I can make adjustments and get this to work for my own scenario. 

Your scenario is also a great one and one I could see myself using. Thanks again!

I'm also interested in learning how to do this in code, but we'll save that for another day. 

In my scenario, I had hoped to create a content type for "sessions" and then create another content type for "time_slots" and use rules to add a "taken" variable to "time_slots" once it was connected to a session. 

The above scenario worked because rules was able to use the current user to update the current node. But, if I have two different types of nodes, only one is current (visible to rules) at a time. So, I wasn't able to figure out how to use the above hints to quite resolve my problem. 

I'm still looking. However, thanks to @apperceptions I am much closer.

[UPDATE: I'm making good progress on a simple solution with custom code. I plan to report back here, once I've got it all working and have gotten some feedback from friends.]

ericfg's picture

The simple and easy code-free method would require some effort to port this module https://www.drupal.org/project/entityreference_prepopulate

using it; views and viewfield I think we could do what you want without code

 

session content type
--title; name/user reference?; details; other info; entity reference to timeslot

timeslot content type
--time/day
--location?/other info
-- viewfield showing sessions that reference this timeslot

 

views:
viewfield view that shows referenced session (used on timeslot content type)
--this view has an "empty text" that shows when there are no referenced nodes. This empty text uses rewrite output to create a link to add a node of type session, it adds the current node id to the create link in a way that the prepopulate module can use to set the value of an entity reference field to the nodeid specified in the link. this link also has &destination=path_to_main_view_where_we_started so the user goes back to your listing of timeslots after submitting the node
-- if there is not a referenced session, the view shows the link to create one. if there is, the view shows the title and other relevant info.

view of timeslot content type, sorted by date/time, showing the viewfield (so it shows a link when there's no session and session info when there is)

I'd be down for helping port that module. it's on my to-do list anyway

I set up another example, this time with two content types as you describe. 

No programming is required for this.  In fact, you don't even need the 'taken' field! :)

Just use a (reverse) reference view for the session nodes' time_slot field.

This is simply a view of all time_slots that do not have a session referencing them. This view has a 'reference' display instead of page or block so that it can be used as a lookup for select options on the session node add form.

Here is the view, with the important options set:

Here is the field def:

Here is the result when adding a second session after I had already taken Time Slot A:

Oops! I forgot to reverse the default sorting in the view! Easy fix!

Along with the simple filter, it's the reverse relationship in the view that makes this all work. The "reverse" option on relationships appears when you add one to a view:

The same technique could be used to display the "taken" status on a time_slot node's display without there actually being a field.

Alternatively, a rule or code could watch for changes to session time slot fields and use the reference to update a time_slot node's taken field if you must have one.  Rules and callbacks have access to old and new values when triggered by a field change. Use those to find the appropriate time slot and set or unset it's taken field.

I hope that applies to your approach.

ericfg's picture

add in entityreference_prepopulate to assist in the workflow and I think we're pointing to the same idea