Scheduling posts, sounds easy enough

What are the hardest parts of programming again?

I’ve been writing a date time picker Vue component for editors to schedule stories for publishing and it is such a beast! The picker itself is now done, but I’m hooking up the scheduler and handling the myriad of possible paths these components can take.

A story can be scheduled, it can be rescheduled, it can be unscheduled, it can be published and therefore unschedul-able. It can also be any one of those things by someone else at the same time so we have to respond to remote changes through sockets.

We also have to handle how to figure out if a story was scheduled already or if the user is currently trying to schedule it—nearly everything on the page autosaves, but not the schedule. Except unscheduling, that does autosave. So how do we know if the datetime that we have in state is the one the user put in, or the one that was already saved, or the one that a remote user just now saved?

We also have to show the current date/time updating live if the user has not scheduled anything, or we have to show the date and time the story was published on if it’s been published or changed. So we need to make sure we don’t think that any of those numbers mean that the user has tried to schedule it, and we also need to make sure that the user doesn’t choose a time in the past (for now, we will allow backdating in the future). With the older implementation of this process, at some point someone was able to publish a story with a future date and no one knows how that could have happened, so make sure to think about that, too.

If you are from the future and you notice this was the last thing I ever wrote, it’s because I threw my computer out the window in frustration, quit my job and moved to the woods.

I think I’ve got all the timezone stuff all nailed down, thanks to our timezone library, so a lot of what’s tricky now is managing a global state (previously scheduled data) versus local state (what the user has inputted) and managing communication between two sibling components that need to be re-usable outside of the parent component.

I’ve decided to go with reactive providers, where the whole shebang is wrapped in a component that manages local state and also grabs the vuex store data to verify what’s what. It seems to be far less cumbersome then what I did originally, which was a lot of emitting of events and repetitive computed properties between 3 components (which all involve comparing dates and formatting them for timezones). It feels a little weird to pass an injected method to the components to update the local state, but I suppose it is basically the same thing as dispatching events in Vuex.

I did not use Vuex for this because we want this data to use the lifecycle hooks of this page/component—when you navigate back to the dashboard, we don’t want it to stick around. I’d have to wipe all the data out of the store on unmount which feels dumb and not like what vuex was meant for. I am guessing that Pinia might be a better solve for this (I actually have no idea), but we aren’t using it yet and I don’t think we plan to any time soon.

The other trick bit of this is testing. Thankfully Jest has a lot of helpful mock timers; I can set a specific system time to mock the current time and increment the setInterval calls manually. I'm still figuring out how to test the reactive providers, since I don't have a ton of experience with this pattern. I think a stubbed mock component to act as the providing source is the way to go; isn't it great how much javascript one must write to test the javascript you already wrote? What's going to test the test? That is certainly a (long) topic for another post.

I think another side of this that makes it extra challenging is that the feature is critical. If stories don't publish when they are supposed to, that is a really big problem. Even if it works "correctly", it also has to be clear to the user when the story will actually publish, which is harder then you might think. We show the user times in the timezone that they set up in their profile, not their system time. If they are traveling in a different timezone, suddenly this all feels less obvious. So we have to put timezone labels on everything.

Don't even talk to me about daylight saving time.

Additional reading on programming and dates