One technique that in my opinion makes the code way simpler is to exit as soon as possible (or "fail early", or "handle-the-error-first", if you'd like). This avoids having multiple nested blocks in your code, plus keeps your mind "clean" because you can be sure that, if the code followed under a given position, you can always be sure the right conditions have been met (and you don't have to worry about them any longer).
For instance, I would rewrite the code as
if (string.IsNullOrEmpty(SessionValues.AccessToken))
return; // fail early
// now we don't have to worry about SessionValues.AccessToken
eventstatuscode = "logged";
EventStatus eventStatus = rb.GetEventStatus();
if (eventStatus == null)
{
eventstatuscode = DateTime.Parse(eventDetails.signUpDeadline) < DateTime.Now ? "expired" : eventstatuscode;
return;
}
// now we don't have to worry about eventStatus
if (string.IsNullOrEmpty(eventStatus.cancelDate))
{
eventstatuscode = eventStatus.onWaitingList ? "waitinglist" : eventstatuscode;
eventstatuscode = eventStatus.onWaitingList == false ? "accepted" : eventstatuscode;
return;
}
eventstatuscode = DateTime.Parse(eventDetails.signUpDeadline) < DateTime.Now ? "expired": eventstatuscode;
Some people might not like this because someone has told them to avoid having multiple return points in a function. But for me, the above is much clearer. Every time I am reading a code that branches into an if-else, I have to keep both in my head, read the if, then go back, read the else as if the 'if' never happened, then start wondering what would be the output if the "if" conditions were met, then the else... back and forth.
This way I can read the if, and when I see it leads to a return, I know I will be able to forget that block to understand the rest of the function. One less thing to have in mind in order to understand the flow of the algorithm. I would apply the same to the ternary operation blocks, likely removing them if they don't lead to any reading improvements.
Plus, whenever I find myself in the middle of the function, I can always know that the bad conditions have already been handled (otherwise the execution cursor wouldn't be in that position in the first place). And if the execution shouldn't be there but is, I can quickly realize where the bug was (in the condition checks in the beginning of the function).
By the way, I hope I didn't introduce any mistakes in this refactoring as I didn't test it. I believe I might have, because usually I rely heavily on unit testing to get those refactoring artifacts!