Skip to content

Commit

Permalink
Add waiting list registering
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucia Karens authored and Lucia Karens committed Nov 8, 2024
1 parent 329b339 commit 890f41b
Show file tree
Hide file tree
Showing 11 changed files with 230 additions and 38 deletions.
11 changes: 8 additions & 3 deletions events/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,18 @@ def signup(request, event_pk):
"""
Endpoint to signup to events
"""

event = get_object_or_404(Event, pk=event_pk)
if not request.user:
return JsonResponse({"error": "Authentication required."}, status=403)

if not event.open_for_signup:
return JsonResponse({"error": "Event not open for sign ups."}, status=403)

waiting_list = False
if event.is_full():
return JsonResponse({"message": "Event is fully booked."}, status=400)
waiting_list = True
if event.fee_s > 0:
return JsonResponse({"message": "Event is fully booked."}, status=400)

participant, _created = Participant.objects.get_or_create(
user_s=request.user, event=event
Expand Down Expand Up @@ -146,9 +148,12 @@ def signup(request, event_pk):
file=file,
defaults={"answer": answer},
)
if waiting_list:
print("put in waiting list")
participant.in_waiting_list = True

# TODO Check that all required questions have been answered

# participant.in_waiting_list = True
participant.signup_complete = True
participant.save()

Expand Down
18 changes: 18 additions & 0 deletions events/migrations/0036_waiting_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 2.2.24 on 2024-11-07 23:09

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('events', '0035_merge_20241008_1413'),
]

operations = [
migrations.AddField(
model_name='participant',
name='in_waiting_list',
field=models.BooleanField(default=False),
),
]
5 changes: 4 additions & 1 deletion events/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ def is_full(self):
return self.number_of_signups() >= self.event_max_capacity

def number_of_signups(self):
return self.participant_set.count()
# return self.participant_set.count()
return self.participant_set.filter(in_waiting_list=False).count()

class Meta:
ordering = ["date_start", "name"]
Expand Down Expand Up @@ -159,6 +160,8 @@ class Participant(models.Model):
) # None for company representatives, filled in if the
# student has payed using Stripe
fee_payed_s = models.BooleanField(default=False)
# student is in waiting list
in_waiting_list = models.BooleanField(default=False)
attended = models.NullBooleanField(
blank=True, null=True, verbose_name="The participant showed up to the event"
)
Expand Down
5 changes: 4 additions & 1 deletion events/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ def event(event, request):
"open_for_signup_student": event.open_for_signup and event.signup_s,
"open_for_signup_company": event.open_for_signup and event.signup_cr,
"event_max_capacity": event.event_max_capacity,
"participant_count": event.participant_set.count(),
"participant_count": event.participant_set.filter(
in_waiting_list=False
).count(),
"fully_booked": event.is_full(),
}

Expand Down Expand Up @@ -86,6 +88,7 @@ def participant(participant):
"name": participant.assigned_name(),
"fee_payed": participant.fee_payed_s,
"signup_complete": participant.signup_complete,
"in_waiting_list": participant.in_waiting_list,
"team_id": participant.team().id if participant.team() else None,
"team_name": participant.team().name if participant.team() else None,
"is_team_leader": participant.teammember_set.first()
Expand Down
36 changes: 30 additions & 6 deletions events/static/js/signup/components/SignupForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ class SignupForm extends Component {
this.handleChange = this.handleChange.bind(this);
this.handleClick = this.handleClick.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleWaitingList = this.handleWaitingList.bind(this);
this.validate = this.validate.bind(this);
this.showErrors = this.showErrors.bind(this);

}

handleChange(id, value) {
Expand All @@ -55,29 +56,36 @@ class SignupForm extends Component {
handleClick() {
this.handleSubmit("");
}

handleSubmit(intent_id) {
const errors = this.validate();
const {signupUrl, dispatcher} = this.props;

const answers = mapValues(this.state.answers, answer => Array.isArray(answer) ? answer.join(',') : answer);

this.setState({
errors: errors
});

console.log("intent_id", intent_id);
console.log("answers", answers);
if (isEmpty(errors)) {
axios.post(signupUrl, {answers, intent_id}, {
headers: {
"X-CSRFToken": Cookie.get('csrftoken')
}
}).then(response => {
dispatcher(updateParticipant(response.data.participant));
console.log("participant data", response.data.participant);
}
)
}
}

handleWaitingList() {
this.handleSubmit("");
}


validate() {
const {answers, payed}=this.state;
const {signup_questions, fee} = this.props.event;
Expand Down Expand Up @@ -153,6 +161,9 @@ class SignupForm extends Component {
</Fragment>
)}
</Typography>
<Typography style={{marginTop: 16, color: "#B22222", fontSize: 20 }}>
{event.fully_booked ? 'Sorry, this event is fully booked.': ''}
</Typography>
</Grid>
)}
</Grid>
Expand All @@ -161,8 +172,8 @@ class SignupForm extends Component {
<Grid item sm={12}>
<Typography style={{marginTop: 8}}>By signing up you agree to THS Armada's <a href="https://docs.google.com/document/d/14_dUZHTL6QUNF9UeL7fghJXO1wZimbi_aKG5ttcGd1s/edit#heading=h.hpqg0xn5jl2q" target="_blank" rel="noopener noreferrer" style={{ color: "#00d790" }}>Privacy Notice</a>.</Typography>

<Typography style={{marginTop: 16, color: "#B22222", fontSize: 20 }}>
{event.fully_booked ? 'Sorry, this event is fully booked.': ''}
<Typography style={{marginTop: 16, color: "#B22222", fontSize: 18 }}>
{event.fully_booked ? 'Sorry, this event is fully booked. Join the waiting list to automatically get a spot if someone deregisters. Even if you do not get a spot, you can still come to the physical location of the event on the day of. If registered attendees do not show up, you will be given a spot on a first-come first-served basis for all who are on the waiting list.': ''}
</Typography>

<Button
Expand All @@ -174,6 +185,19 @@ class SignupForm extends Component {
>
{open_for_signup ? "Sign Up" : "Not open for sign up"}
</Button>
{event.fully_booked && (
<Button

onClick={this.handleWaitingList}
variant="contained"
color="secondary"
style={{marginTop: 10, marginLeft: 20}}
>
{"Join Waiting List"}
</Button>


)}
</Grid>
)}
</Grid>
Expand Down
63 changes: 63 additions & 0 deletions events/static/js/signup/components/WaitingListPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React, {Component, Fragment} from 'react';
import Typography from "@material-ui/core/es/Typography/Typography";
import Button from "@material-ui/core/es/Button/Button";
import Grid from "@material-ui/core/es/Grid/Grid";


class WaitingListPage extends Component {
constructor(props) {
super(props);
}


render() {
const {event} = this.props;


return (
<Grid container spacing={16}>
<div className='image-section' >
{
event.image_url && (
<img alt='Event image' src={event.image_url} style={{"max-width":"100%",}}/>
)
}
</div>


<Grid item sm={12}>
<Typography style={{marginTop: 8}}>By signing up you agree to THS Armada's <a href="https://docs.google.com/document/d/14_dUZHTL6QUNF9UeL7fghJXO1wZimbi_aKG5ttcGd1s/edit#heading=h.hpqg0xn5jl2q" target="_blank" rel="noopener noreferrer" style={{ color: "#00d790" }}>Privacy Notice</a>.</Typography>

<Typography style={{marginTop: 16, color: "#d73030", fontSize: 18 }}>
{'You have already joined the waiting list for this event.'}
</Typography>
<Typography style={{marginTop: 16, fontSize: 18 }}>
{'If a spot opens up for you, you will automatically be added to the event. Even if you do not get a spot, you can still come to the physical location of the event on the day of: if registered attendees do not show up, you (and all other people on the waiting list) will be given a spot on a first-come first-served basis.'}
</Typography>

<Button
disabled="true"
variant="contained"
color="primary"
style={{marginTop: 10}}
>
{"Not open for sign up"}
</Button>

<Button
disabled="true"
variant="contained"
color="secondary"
style={{marginTop: 10, marginLeft: 20}}
>
{"Join Waiting List"}
</Button>

</Grid>

</Grid>
)
}
}

export default WaitingListPage;
9 changes: 8 additions & 1 deletion events/static/js/signup/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import theme from 'armada/theme';
import MuiThemeProvider from "@material-ui/core/es/styles/MuiThemeProvider";
import SignupForm from "./components/SignupForm";
import Manage from './components/Manage';
import WaitingListPage from './components/WaitingListPage';
import Header from "./components/Header";
import reducer from './reducer';
import compose from 'recompose/compose';
import {init} from './actions';
import keyBy from 'lodash/keyBy';
import withWidth from "@material-ui/core/es/withWidth/withWidth";


const generateClassName = createGenerateClassName({
dangerouslyUseGlobalCSS: false,
productionPrefix: 'c'
Expand Down Expand Up @@ -67,7 +69,7 @@ class App extends Component {
className={classes.root}
>
<Header event={event}/>
{participant.signup_complete ? (
{(participant.signup_complete && !participant.in_waiting_list)? (
<Manage
participantId={participant.id}
checkInToken={participant.check_in_token}
Expand All @@ -77,6 +79,11 @@ class App extends Component {
teams={teams}
dispatcher={this.dispatcher}
/>
) : (participant.signup_complete && participant.in_waiting_list)? (
<WaitingListPage
event = {event}
dispatcher = {this.dispatcher}
/>
) : (
<SignupForm
event={event}
Expand Down
2 changes: 1 addition & 1 deletion templates/events/emails.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ <h1>E-mail addresses</h1>
</style>

<textarea>
{% for participant in participants|dictsort:"timestamp" %}{{ participant.assigned_name }} <{{ participant.assigned_email }}> {% if not forloop.last %}, {% endif %}{% endfor %}
{% for participant in participants|dictsort:"timestamp" %}{% if not participant.in_waiting_list %}{{ participant.assigned_name }} <{{ participant.assigned_email }}> {% if not forloop.last %}, {% endif %} {% endif%} {% endfor %}
</textarea>
8 changes: 8 additions & 0 deletions templates/events/event_edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ <h1>{{ event.name }}</h1>
</li>

<li role="presentation"><a href="#emails" aria-controls="emails" role="tab" data-toggle="tab">E-mails</a></li>

<li role="presentation"><a href="#waiting_list" aria-controls="waiting_list" role="tab" data-toggle="tab">Waiting List
({{ event.participant_count}})</a>
</li>


</ul>

Expand All @@ -38,6 +43,9 @@ <h1>{{ event.name }}</h1>
<div role="tabpanel" class="tab-pane" id="emails">
{% include 'events/emails.html' with participants=participants %}
</div>
<div role="tabpanel" class="tab-pane" id="waiting_list">
{% include 'events/waiting_list_list.html' with participants=participants questions=questions %}
</div>
</div>
{% endblock %}

Expand Down
52 changes: 27 additions & 25 deletions templates/events/participant_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,34 @@

<tbody>
{% for participant in participants %}
<tr>
<td style="white-space: nowrap;">
{% if participant.user_s %} <a href="{% url 'people:profile' fair.year participant.user_s.pk %}">{{ participant.assigned_name }}</a>
{% else %}{{ participant.assigned_name }}{% endif %}
</td>
<td style="white-space: nowrap;">{% if participant.timestamp %}<span style="display: none;">{{ participant.timestamp|date:"U" }}</span>{{ participant.timestamp }}{% endif %}</td>
<td>{{ participant.teammember_set.first.team.name }}</td>
<td><a href="mailto:{{ participant.assigned_email }}">{{ participant.assigned_email }}</a></td>
<td>{% if participant.assigned_phone_number %}<a href="tel:{{ participant.assigned_phone_number }}">{{ participant.assigned_phone_number }}</a>{% endif %}</td>

<td>
{% if participant.user_cr %} Company rep.
{% else %} Student {% endif %}
</td>
{% for answer in participant.signupquestionanswer_set.all %}
<td style="text-align: right;">
{% if answer.file %}
<a href="{{ answer.file.file.url }}" target="_blank">
Download File
</a>
{% else %}
{{ answer.answer }}
{% endif %}
{% if not participant.in_waiting_list %}
<tr>
<td style="white-space: nowrap;">
{% if participant.user_s %} <a href="{% url 'people:profile' fair.year participant.user_s.pk %}">{{ participant.assigned_name }}</a>
{% else %}{{ participant.assigned_name }}{% endif %}
</td>
{% endfor %}
</tr>
<td style="white-space: nowrap;">{% if participant.timestamp %}<span style="display: none;">{{ participant.timestamp|date:"U" }}</span>{{ participant.timestamp }}{% endif %}</td>
<td>{{ participant.teammember_set.first.team.name }}</td>
<td><a href="mailto:{{ participant.assigned_email }}">{{ participant.assigned_email }}</a></td>
<td>{% if participant.assigned_phone_number %}<a href="tel:{{ participant.assigned_phone_number }}">{{ participant.assigned_phone_number }}</a>{% endif %}</td>

<td>
{% if participant.user_cr %} Company rep.
{% else %} Student {% endif %}
</td>
{% for answer in participant.signupquestionanswer_set.all %}
<td style="text-align: right;">
{% if answer.file %}
<a href="{{ answer.file.file.url }}" target="_blank">
Download File
</a>
{% else %}
{{ answer.answer }}
{% endif %}
</td>
{% endfor %}
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
Expand Down
Loading

0 comments on commit 890f41b

Please sign in to comment.