diff --git a/backend/RxcVoiceApi/main/authviews.py b/backend/RxcVoiceApi/main/authviews.py index 0d57f027..173a32b4 100644 --- a/backend/RxcVoiceApi/main/authviews.py +++ b/backend/RxcVoiceApi/main/authviews.py @@ -35,7 +35,21 @@ class DelegateList(mixins.CreateModelMixin, authentication_classes = [TokenAuthentication] def get(self, request, *args, **kwargs): - return self.list(request, *args, **kwargs) + profile_id = self.kwargs['profile_id'] + try: + profile = Profile.objects.get(id=profile_id) + except Profile.DoesNotExist: + profile = None + if profile != None: + delegates = profile.delegates.all() + page = self.paginate_queryset(delegates) + if page is not None: + serializer = self.get_serializer(page, many=True) + return self.get_paginated_response(serializer.data) + serializer = self.get_serializer(delegates, many=True) + return Response(serializer.data) + else: + return Response(status=status.HTTP_400_BAD_REQUEST) def post(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) @@ -146,7 +160,21 @@ class GroupList(mixins.CreateModelMixin, authentication_classes = [TokenAuthentication] def get(self, request, *args, **kwargs): - return self.list(request, *args, **kwargs) + user_id = self.kwargs['user_id'] + try: + user = User.objects.get(id=user_id) + except User.DoesNotExist: + user = None + if user != None: + groups = user.groups.all() + page = self.paginate_queryset(groups) + if page is not None: + serializer = self.get_serializer(page, many=True) + return self.get_paginated_response(serializer.data) + serializer = self.get_serializer(groups, many=True) + return Response(serializer.data) + else: + return Response(status=status.HTTP_400_BAD_REQUEST) def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs) diff --git a/backend/RxcVoiceApi/main/models.py b/backend/RxcVoiceApi/main/models.py index a7b8d091..795485ba 100644 --- a/backend/RxcVoiceApi/main/models.py +++ b/backend/RxcVoiceApi/main/models.py @@ -8,6 +8,7 @@ class Process(models.Model): id = models.AutoField(primary_key=True, editable=False) title = models.CharField(max_length=256, blank=False) description = models.TextField(blank=True, null=True) + invitation_message = models.TextField(blank=True, null=True) start_date = models.DateTimeField(blank=False) end_date = models.DateTimeField(blank=False) groups = models.ManyToManyField(Group, blank=True, default=[]) @@ -54,10 +55,10 @@ def __str__(self): class Delegate(models.Model): id = models.AutoField(primary_key=True, editable=False) profile = models.ForeignKey( - Profile, related_name='delegates', blank=True, null=True, on_delete=models.CASCADE) + Profile, related_name='delegates', on_delete=models.CASCADE) invited_by = models.ForeignKey( Profile, related_name='delegates_invited', blank=True, null=True, on_delete=models.SET_NULL) - process = models.ForeignKey(Process, related_name='delegates', null=True, on_delete=models.SET_NULL) + process = models.ForeignKey(Process, related_name='delegates', on_delete=models.CASCADE) credit_balance = models.DecimalField( default=0, blank=True, max_digits=6, decimal_places=0) # must be staff to change from default @@ -83,7 +84,7 @@ class Stage(PolymorphicModel): description = models.TextField(blank=True) start_date = models.DateTimeField(blank=False) end_date = models.DateTimeField(blank=False) - process = models.ForeignKey(Process, related_name='stages', null=True, on_delete=models.SET_NULL) + process = models.ForeignKey(Process, related_name='stages', on_delete=models.CASCADE) position = models.DecimalField( default=0, max_digits=2, decimal_places=0, editable=True) diff --git a/backend/RxcVoiceApi/main/processviews.py b/backend/RxcVoiceApi/main/processviews.py index 44294e7c..150966ab 100644 --- a/backend/RxcVoiceApi/main/processviews.py +++ b/backend/RxcVoiceApi/main/processviews.py @@ -3,9 +3,10 @@ from rest_framework.authentication import TokenAuthentication from rest_framework import generics, mixins, status from django.db.models import Q -from .serializers import ProcessSerializer, TransferSerializer +from .serializers import ProfileSerializer, ProcessSerializer, TransferSerializer, DelegateSerializer, StageSerializer, DelegationSerializer, ConversationSerializer, ElectionSerializer from .permissions import ProcessPermission, TransferPermission -from .models import Process, Transfer, MatchPayment +from .models import Process, Transfer, MatchPayment, Stage, Delegate, Profile +from django.contrib.auth.models import Group, User from guardian.shortcuts import assign_perm from django.utils import timezone from .services import estimate_match @@ -38,16 +39,96 @@ def get(self, request, *args, **kwargs): return Response(serializer.data) def post(self, request, *args, **kwargs): - serializer = self.get_serializer(data=request.data) + # create process object + serializer = self.get_serializer(data=request.data['process']) serializer.is_valid(raise_exception=True) self.perform_create(serializer) process_id = serializer.data.get('id') process_object = Process.objects.get(pk=process_id) + # create stages + stages = request.data['stages'] + for stage in stages: + stage['process'] = process_id + if stage['type'] == Stage.DELEGATION: + stage_serializer = DelegationSerializer(data=stage) + stage_serializer.is_valid(raise_exception=True) + DelegationSerializer.create( + DelegationSerializer(), + validated_data=stage_serializer.validated_data, + ) + elif stage['type'] == Stage.CONVERSATION: + stage_serializer = ConversationSerializer(data=stage) + stage_serializer.is_valid(raise_exception=True) + ConversationSerializer.create( + ConversationSerializer(), + validated_data=stage_serializer.validated_data, + ) + elif stage['type'] == Stage.ELECTION: + stage_serializer = ElectionSerializer(data=stage) + stage_serializer.is_valid(raise_exception=True) + ElectionSerializer.create( + ElectionSerializer(), + validated_data=stage_serializer.validated_data, + ) + else: + stage_serializer = StageSerializer(data=stage) + stage_serializer.is_valid(raise_exception=True) + StageSerializer.create( + StageSerializer(), + validated_data=stage_serializer.validated_data, + ) + # create new group if necessary + group_data = request.data['group'] + if group_data['create']: + new_group = Group.objects.create(name=group_data['name']) + new_group.save() + process_object.groups.add(new_group) + request.user.groups.add(new_group) + # create new delegates if necessary + existing_groups = process_object.groups.all() + for existing_group in existing_groups: + assign_perm('can_view', existing_group, process_object) + for user in existing_group.user_set.all(): + Delegate.objects.create( + profile=user.profile, + process=process_object, + credit_balance=request.data['stages'][0]['num_credits'], + invited_by=request.user.profile, + ) + invites = request.data['invites'] + if invites: + for delegate in invites: + delegate['process'] = process_id + if group_data['create']: + delegate['profile']['user']['groups'].append(new_group.id) + for existing_group in existing_groups: + delegate['profile']['user']['groups'].append(existing_group.id) + try: + profile_data = delegate['profile'] + try: + existing_user = User.objects.get(email=profile_data['user']['email']) + except: + existing_user = None + if existing_user is not None: + profile = Profile.objects.get(user=existing_user) + else: + profile_serializer = ProfileSerializer(data=profile_data) + profile_serializer.is_valid(raise_exception=True) + profile = ProfileSerializer.create( + ProfileSerializer(), + validated_data=profile_serializer.validated_data, + set_unusable_password=True, + ) + Delegate.objects.create( + credit_balance=delegate['credit_balance'], + profile=profile, + process=process_object, + invited_by=request.user.profile, + ) + except: + print("could not create user") headers = self.get_success_headers(serializer.data) # assign can_view permission to any groups the process belongs to. - groups = process_object.groups.all() - for group in groups: - assign_perm('can_view', group, process_object) return Response( serializer.data, status=status.HTTP_201_CREATED, @@ -87,8 +168,6 @@ def delete(self, request, *args, **kwargs): return self.destroy(request, *args, **kwargs) - - class TransferList(mixins.CreateModelMixin, mixins.ListModelMixin, generics.GenericAPIView): @@ -129,8 +208,6 @@ def post(self, request, *args, **kwargs): headers=headers) - - class EstimateMatch(mixins.CreateModelMixin, mixins.ListModelMixin, generics.GenericAPIView): diff --git a/backend/RxcVoiceApi/main/serializers.py b/backend/RxcVoiceApi/main/serializers.py index c8ed8c1a..108b74f0 100644 --- a/backend/RxcVoiceApi/main/serializers.py +++ b/backend/RxcVoiceApi/main/serializers.py @@ -127,10 +127,17 @@ def create(self, validated_data): class GroupSerializer(serializers.ModelSerializer): + def __init__(self, *args, **kwargs): + super(GroupSerializer, self).__init__(*args, **kwargs) + self.fields['users'] = serializers.SerializerMethodField() + class Meta: model = Group fields = '__all__' + def get_users(self, obj): + return map(lambda user: user.first_name + " " + user.last_name, obj.user_set.all()) + class PermissionSerializer(serializers.ModelSerializer): class Meta: @@ -252,23 +259,13 @@ def get_pending_credits(self, obj): total += transfer.amount return total - def create(self, validated_data, set_unusable_password): - profile_data = validated_data.get('profile') - try: - existing_user = User.objects.get(email=profile_data['user']['email']) - except User.DoesNotExist: - existing_user = None - if existing_user is not None: - profile = Profile.objects.get(user=existing_user) - else: - profile = ProfileSerializer.create( - ProfileSerializer(), - validated_data=profile_data, - set_unusable_password=set_unusable_password - ) + def create(self, validated_data): + invited_by = None + if validated_data.get('invited_by'): + invited_by = validated_data.get('invited_by').profile delegate, created = Delegate.objects.update_or_create( - profile=profile, - invited_by=validated_data.get('invited_by').profile, + profile=validated_data.get('profile'), + invited_by=invited_by, process=validated_data.get('process'), credit_balance=validated_data.get('credit_balance', 0), ) @@ -460,10 +457,11 @@ def create(self, validated_data): class ProcessSerializer(serializers.ModelSerializer): def __init__(self, *args, **kwargs): super(ProcessSerializer, self).__init__(*args, **kwargs) - self.fields['stages'] = StageSerializer(many=True, context=self.context) + self.fields['stages'] = StageSerializer(many=True, context=self.context, required=False) self.fields['delegates'] = DelegateSerializer( many=True, - context={'allowed_fields': ['id', 'profile', 'invited_by', 'process', 'credit_balance', 'pending_credits']} + context={'allowed_fields': ['id', 'profile', 'invited_by', 'process', 'credit_balance', 'pending_credits']}, + required=False, ) class Meta: @@ -474,6 +472,7 @@ def create(self, validated_data): process = Process.objects.create( title=validated_data.get('title'), description=validated_data.get('description'), + invitation_message=validated_data.get('invitation_message'), start_date=validated_data.get('start_date'), end_date=validated_data.get('end_date'), ) diff --git a/backend/RxcVoiceApi/main/urls.py b/backend/RxcVoiceApi/main/urls.py index 6b0a951a..d9bdb5cd 100644 --- a/backend/RxcVoiceApi/main/urls.py +++ b/backend/RxcVoiceApi/main/urls.py @@ -4,7 +4,7 @@ from .authviews import (DelegateList, DelegateDetail, ProfileList, ProfileDetail, UserDetail, CustomAuthToken, PermissionList, EmailApplication, GroupList, GetGithubUser, ValidateAuthToken, - GetTwitterToken, ForgotPassword, ResetPassword) + GetTwitterToken, ForgotPassword, ResetPassword, GroupList) from .electionviews import (ElectionList, ElectionDetail, ProposalList, VoteList) from .conversationviews import (ConversationList, ConversationDetail) @@ -18,9 +18,11 @@ path('profile/', ProfileList.as_view(), name='profile-list'), path('profiles//', ProfileDetail.as_view(), name='profile-detail'), - path('delegates/', DelegateList.as_view(), name='delegate-list'), + path('profile//delegates', DelegateList.as_view(), name='delegate-list'), path('delegates//', DelegateDetail.as_view(), name='delegate-detail'), + path('users//groups', GroupList.as_view(), + name='group-list'), path('users//', UserDetail.as_view(), name='user-detail'), path('groups/', GroupList.as_view(), name='group-list'), diff --git a/rxc-voice/package-lock.json b/rxc-voice/package-lock.json index f9db0b53..dc47dd43 100644 --- a/rxc-voice/package-lock.json +++ b/rxc-voice/package-lock.json @@ -19,6 +19,7 @@ "react": "^17.0.1", "react-alert": "^7.0.2", "react-alert-template-basic": "^1.0.0", + "react-datetime": "^3.1.1", "react-dom": "^17.0.1", "react-router-dom": "^5.2.0", "react-scripts": "4.0.3", @@ -2286,6 +2287,7 @@ "jest-resolve": "^26.6.2", "jest-util": "^26.6.2", "jest-worker": "^26.6.2", + "node-notifier": "^8.0.0", "slash": "^3.0.0", "source-map": "^0.6.0", "string-length": "^4.0.1", @@ -5217,6 +5219,7 @@ "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", + "fsevents": "~2.3.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", @@ -7134,7 +7137,8 @@ "esprima": "^4.0.1", "estraverse": "^5.2.0", "esutils": "^2.0.2", - "optionator": "^0.8.1" + "optionator": "^0.8.1", + "source-map": "~0.6.1" }, "bin": { "escodegen": "bin/escodegen.js", @@ -11021,6 +11025,7 @@ "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", + "fsevents": "^2.1.2", "graceful-fs": "^4.2.4", "jest-regex-util": "^26.0.0", "jest-serializer": "^26.6.2", @@ -12130,6 +12135,7 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dependencies": { + "graceful-fs": "^4.1.6", "universalify": "^2.0.0" }, "optionalDependencies": { @@ -15544,6 +15550,18 @@ "node": ">=10" } }, + "node_modules/react-datetime": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/react-datetime/-/react-datetime-3.1.1.tgz", + "integrity": "sha512-gHCTjAniCcMb6jdXpz+MpVe/uCeaHNDOofg+l41nLlJI3uBLBMV40CQbGB2TCTUpCzGT1mCs4vQzKGMjXO/WWQ==", + "dependencies": { + "prop-types": "^15.5.7" + }, + "peerDependencies": { + "moment": "^2.16.0", + "react": "^16.5.0 || ^17.0.0" + } + }, "node_modules/react-dev-utils": { "version": "11.0.4", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz", @@ -15877,6 +15895,7 @@ "eslint-webpack-plugin": "^2.5.2", "file-loader": "6.1.1", "fs-extra": "^9.0.1", + "fsevents": "^2.1.3", "html-webpack-plugin": "4.5.0", "identity-obj-proxy": "3.0.0", "jest": "26.6.0", @@ -19402,8 +19421,10 @@ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", "dependencies": { + "chokidar": "^3.4.1", "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0" + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.1" }, "optionalDependencies": { "chokidar": "^3.4.1", @@ -19493,6 +19514,7 @@ "anymatch": "^2.0.0", "async-each": "^1.0.1", "braces": "^2.3.2", + "fsevents": "^1.2.7", "glob-parent": "^3.1.0", "inherits": "^2.0.3", "is-binary-path": "^1.0.0", @@ -19916,6 +19938,7 @@ "anymatch": "^2.0.0", "async-each": "^1.0.1", "braces": "^2.3.2", + "fsevents": "^1.2.7", "glob-parent": "^3.1.0", "inherits": "^2.0.3", "is-binary-path": "^1.0.0", @@ -20443,6 +20466,9 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dependencies": { + "graceful-fs": "^4.1.6" + }, "optionalDependencies": { "graceful-fs": "^4.1.6" } @@ -20931,6 +20957,9 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dependencies": { + "graceful-fs": "^4.1.6" + }, "optionalDependencies": { "graceful-fs": "^4.1.6" } @@ -33236,6 +33265,14 @@ "whatwg-fetch": "^3.4.1" } }, + "react-datetime": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/react-datetime/-/react-datetime-3.1.1.tgz", + "integrity": "sha512-gHCTjAniCcMb6jdXpz+MpVe/uCeaHNDOofg+l41nLlJI3uBLBMV40CQbGB2TCTUpCzGT1mCs4vQzKGMjXO/WWQ==", + "requires": { + "prop-types": "^15.5.7" + } + }, "react-dev-utils": { "version": "11.0.4", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz", diff --git a/rxc-voice/package.json b/rxc-voice/package.json index 49a67d58..5d06a013 100644 --- a/rxc-voice/package.json +++ b/rxc-voice/package.json @@ -18,6 +18,7 @@ "react": "^17.0.1", "react-alert": "^7.0.2", "react-alert-template-basic": "^1.0.0", + "react-datetime": "^3.1.1", "react-dom": "^17.0.1", "react-router-dom": "^5.2.0", "react-scripts": "4.0.3", diff --git a/rxc-voice/src/App.scss b/rxc-voice/src/App.scss index a10f8f47..3f802371 100644 --- a/rxc-voice/src/App.scss +++ b/rxc-voice/src/App.scss @@ -42,6 +42,21 @@ p { font-weight: normal; } +button { + display: block; + margin: 1em auto 1em auto; + background: black; + color: white; + border: 1px solid black; + border-radius: 15px; + padding: .5em 1em .5em 1em; + outline: none; + cursor: pointer; +} +button:hover { + opacity: 0.8; +} + .explain-text { font-size: 1rem; line-height: 1.3rem; diff --git a/rxc-voice/src/App.tsx b/rxc-voice/src/App.tsx index db2897d2..4f77de1f 100644 --- a/rxc-voice/src/App.tsx +++ b/rxc-voice/src/App.tsx @@ -1,6 +1,7 @@ import React, { useContext } from 'react'; import { Redirect, Route, Switch } from "react-router-dom"; import { StateContext } from './hooks'; +import "react-datetime/css/react-datetime.css"; import Home from "./components/Home"; import CreateEvent from "./components/CreateEvent"; import Header from './components/Header'; diff --git a/rxc-voice/src/components/Account/Account.scss b/rxc-voice/src/components/Account/Account.scss index a448ed85..b40fa930 100644 --- a/rxc-voice/src/components/Account/Account.scss +++ b/rxc-voice/src/components/Account/Account.scss @@ -13,6 +13,7 @@ border: none; outline: none; background: inherit; + color: black; cursor: pointer; } .account-button:hover { diff --git a/rxc-voice/src/components/Account/Account.tsx b/rxc-voice/src/components/Account/Account.tsx index 15c75cd3..57855a30 100644 --- a/rxc-voice/src/components/Account/Account.tsx +++ b/rxc-voice/src/components/Account/Account.tsx @@ -14,7 +14,6 @@ function Account() { // const github_client_id = 'f9be73dc7af4857809e0'; const { logoutUser, setUserData } = useContext(ActionContext); const user: User | undefined = getUserData(); - console.log(user) const [editMode, setEditMode] = useState(false); const [email, setEmail] = useState(user ? user.email : ""); diff --git a/rxc-voice/src/components/CreateEvent/CreateEvent.scss b/rxc-voice/src/components/CreateEvent/CreateEvent.scss index e69de29b..4f151782 100644 --- a/rxc-voice/src/components/CreateEvent/CreateEvent.scss +++ b/rxc-voice/src/components/CreateEvent/CreateEvent.scss @@ -0,0 +1,81 @@ +.create-event { + max-width: 700px; + padding: 0 20px; + margin: 0 auto; + text-align: left; + + .create-event_header { + text-align: center; + } + + .event-section { + width: calc(100% - 30px); + margin: 3rem auto; + padding: 15px; + border: 1px solid black; + border-radius: 8px; + } + + .event-section > label { + font-size: 23px; + } + + .event-section > p { + margin: 1rem 0; + } + + .event-section_form { + margin: 20px 0; + width: calc(100% - 10px); + } + + .checkbox-button { + margin: auto 0; + } + + .checkbox-form { + display: grid; + grid-template-columns: auto 1fr; + } + + .checkbox-form > .event-section_form_input { + width: calc(100% - 30px); + margin: 0 auto; + font-size: 20px; + } + + .event-section_form_input { + display: block; + width: calc(100% - 30px); + font-size: 20px; + font-family: var(--secondaryFont); + } + + .select-invites { + margin: .5rem 0 1.5rem 0; + } + + .event-section_form_input > input { + margin-right: 1rem; + } + + .event-section_datetime > input { + width: calc(100% - 10px); + font-size: 26px !important; + border: 1px solid black; + border-radius: 5px; + margin-top: 15px; + padding: 5px 0px 5px 5px; + } + + #existing-group_select { + width: calc(100% - 22px); + } + + #match-pool-radio > .event-section_form_input { + margin-top: 20px; + margin-bottom: 20px; + } + + +} diff --git a/rxc-voice/src/components/CreateEvent/CreateEvent.tsx b/rxc-voice/src/components/CreateEvent/CreateEvent.tsx index 4209d420..e85da02d 100644 --- a/rxc-voice/src/components/CreateEvent/CreateEvent.tsx +++ b/rxc-voice/src/components/CreateEvent/CreateEvent.tsx @@ -1,11 +1,314 @@ -import React from "react"; +import React, { useContext, useEffect, useReducer, useState } from "react"; +import moment from "moment"; +import Datetime from "react-datetime"; +import { ActionContext } from "../../hooks"; +import { BgColor } from "../../models/BgColor"; +import { Group } from "../../models/Group"; +import { Stage, StageType } from "../../models/Stage"; +import { User } from "../../models/User"; +import { WebService } from "../../services"; +import { defaultStages, Domain, getUserData } from "../../utils"; +import DelegationSettings from "./components/DelegationSettings"; +import DeliberationSettings from "./components/DeliberationSettings"; +import ElectionSettings from "./components/ElectionSettings"; +import { Delegate } from "../../models/Delegate"; import "./CreateEvent.scss"; +export interface Change { + id: number, + field: string, + value: any, +} + function CreateEvent() { + const { setColor, setUserData } = useContext(ActionContext); + const [eventTitle, setEventTitle] = useState(""); + const [eventDescription, setEventDescription] = useState("") + const [eventStartDate, setEventStartDate] = useState(moment().format()); + const [eventEndDate, setEventEndDate] = useState(moment().add(4, "days").format()); + const [groups, setGroups] = useState(new Array()) + const [newGroup, setNewGroup] = useState(""); + const [existingGroup, setExistingGroup] = useState(""); + const [newGroupName, setNewGroupName] = useState(""); + const [groupMembers, setGroupMembers] = useState(new Array()); + const [invites, setInvites] = useState(""); + const [invitationMessage, setInvitationMessage] = useState("") + + function stageReducer(stages: Stage[], change: Change) { + stages = stages.map((stage: Stage) => { + if (stage.id === change.id) { + stage = { + ...stage, + [change.field]: change.value, + } + } + return stage; + }); + return stages; + }; + const [stages, stageDispatch] = useReducer(stageReducer, defaultStages); + const [loading, setLoading] = useState(true); + + useEffect(() => { + setColor(BgColor.White); + const user: User | undefined = getUserData(); + if (user) { + WebService.fetchGroups(user.user_id) + .subscribe((data: Group[]) => { + setGroups(data); + }); + } + setLoading(false); + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const changeExistingGroup = (groupId: string) => { + setExistingGroup(groupId); + const group = groups.find((group: Group) => { + return group.id === +groupId; + }); + setGroupMembers(group ? group.users : []); + }; + + const createEvent = (e: any) => { + e.preventDefault() + let eventGroup = groups.find((group: Group) => { + return group.id === +existingGroup; + }); + const eventData = { + process: { + title: eventTitle, + description: eventDescription, + invitation_message: invitationMessage, + start_date: eventStartDate, + end_date: eventEndDate, + groups: eventGroup ? [eventGroup.id] : [], + }, + group: { + create: newGroup === "true" ? true : false, + name: newGroupName, + }, + invites: invites.split("\n").map((email: string) => ({ + credit_balance: stages.map((stage: Stage): any => { + return stage; + })[0].num_credits, + profile: { + user: { + username: email, + email: email, + first_name: "", + last_name: "", + password: "email", + groups: [] + } + } + })), + stages: stages, + } + WebService.postProcess(eventData).subscribe(async (data) => { + if (data.ok) { + const user: User | undefined = getUserData(); + if (user) { + WebService.fetchDelegates(user.id) + .subscribe((data: Delegate[]) => { + let updatedUser: User = user; + updatedUser.delegates = data + setUserData(updatedUser) + }); + } + window.location.href = Domain.WEB; + } else { + const error = await data.json(); + Object.keys(error).forEach((key) => { + console.log(error[key]); + }); + } + }); + }; + + const renderSettings = (stage: any) => { + switch (stage.type) { + case StageType.Delegation: + return + case StageType.Conversation: + return + case StageType.Election: + return + } + }; return ( -
Here's some stuff
+
+
+

Create a new Event

+

Fill out the information below to create your event.

+
+

General Information

+

Fill out the general information for this event.

+
+ +

Add a title to this event.

+
+ setEventTitle(e.target.value)} + /> +
+
+
+ +

Add a description to this event.

+
+