From bd3146f41337f97af713b0061ca86ec54cbbcdce Mon Sep 17 00:00:00 2001 From: Tanner Collin Date: Mon, 13 Jan 2020 03:18:41 +0000 Subject: [PATCH] Add address and minor fields to member in API and client --- apiserver/apiserver/api/models.py | 31 ++++++++----- apiserver/apiserver/api/serializers.py | 38 +++++++++------- apiserver/import_old_portal.py | 10 +++++ webclient/src/Account.js | 45 +++++++++++++++++-- webclient/src/App.js | 4 +- webclient/src/Home.js | 61 +------------------------- 6 files changed, 98 insertions(+), 91 deletions(-) diff --git a/apiserver/apiserver/api/models.py b/apiserver/apiserver/api/models.py index 7448a50..7be265b 100644 --- a/apiserver/apiserver/api/models.py +++ b/apiserver/apiserver/api/models.py @@ -7,25 +7,32 @@ from . import old_models class Member(models.Model): user = models.OneToOneField(User, blank=True, null=True, on_delete=models.SET_NULL) + photo_large = models.CharField(max_length=64, blank=True, null=True) + photo_medium = models.CharField(max_length=64, blank=True, null=True) + photo_small = models.CharField(max_length=64, blank=True, null=True) + + set_details = models.BooleanField(default=False) first_name = models.CharField(max_length=32) last_name = models.CharField(max_length=32) + preferred_name = models.CharField(max_length=32) + phone = models.CharField(max_length=32, null=True) + emergency_contact_name = models.CharField(max_length=64, blank=True) + emergency_contact_phone = models.CharField(max_length=32, blank=True) + birthdate = models.DateField(blank=True, null=True) + is_minor = models.BooleanField(default=False) + guardian_name = models.CharField(max_length=32, blank=True, null=True) + street_address = models.CharField(max_length=32, null=True) + city = models.CharField(default='Calgary, AB', max_length=32) + postal_code = models.CharField(max_length=16, null=True) - set_details = models.BooleanField(default=False) is_director = models.BooleanField(default=False) is_instructor = models.BooleanField(default=False) - preferred_name = models.CharField(max_length=32, blank=True) - status = models.CharField(max_length=32, blank=True) - phone = models.CharField(max_length=32, blank=True) - expire_date = models.DateField(default=date.today, blank=True, null=True) - current_start_date = models.DateField(default=date.today, blank=True, null=True) - application_date = models.DateField(default=date.today, blank=True, null=True) + status = models.CharField(max_length=32, blank=True, null=True) + expire_date = models.DateField(default=date.today, null=True) + current_start_date = models.DateField(default=date.today, null=True) + application_date = models.DateField(default=date.today, null=True) vetted_date = models.DateField(blank=True, null=True) monthly_fees = models.IntegerField(default=55, blank=True, null=True) - emergency_contact_name = models.CharField(max_length=64, blank=True) - emergency_contact_phone = models.CharField(max_length=32, blank=True) - photo_large = models.CharField(max_length=64, blank=True, null=True) - photo_medium = models.CharField(max_length=64, blank=True, null=True) - photo_small = models.CharField(max_length=64, blank=True, null=True) class Transaction(models.Model): user = models.ForeignKey(User, related_name='transactions', blank=True, null=True, on_delete=models.SET_NULL) diff --git a/apiserver/apiserver/api/serializers.py b/apiserver/apiserver/api/serializers.py index 8844652..735577d 100644 --- a/apiserver/apiserver/api/serializers.py +++ b/apiserver/apiserver/api/serializers.py @@ -44,22 +44,6 @@ def process_image(upload): -class UserTrainingSerializer(serializers.ModelSerializer): - class Meta: - model = models.Training - exclude = ['user'] - depth = 2 - -class UserSerializer(serializers.ModelSerializer): - training = UserTrainingSerializer(many=True) - - class Meta: - model = User - fields = ['id', 'username', 'member', 'transactions', 'cards', 'training'] - depth = 1 - - - # member viewing member list or other member class OtherMemberSerializer(serializers.ModelSerializer): q = serializers.CharField(write_only=True, max_length=64) @@ -79,6 +63,11 @@ class UserEmailField(serializers.ModelField): class MemberSerializer(serializers.ModelSerializer): photo = serializers.ImageField(write_only=True, required=False) email = UserEmailField(serializers.EmailField) + phone = serializers.CharField() + street_address = serializers.CharField() + city = serializers.CharField() + postal_code = serializers.CharField() + class Meta: model = models.Member fields = '__all__' @@ -126,6 +115,23 @@ class AdminMemberSerializer(MemberSerializer): +class UserTrainingSerializer(serializers.ModelSerializer): + class Meta: + model = models.Training + exclude = ['user'] + depth = 2 + +class UserSerializer(serializers.ModelSerializer): + training = UserTrainingSerializer(many=True) + member = MemberSerializer() + + class Meta: + model = User + fields = ['id', 'username', 'member', 'transactions', 'cards', 'training'] + depth = 1 + + + class TransactionSerializer(serializers.ModelSerializer): class Meta: model = models.Transaction diff --git a/apiserver/import_old_portal.py b/apiserver/import_old_portal.py index 65eeaaa..ff6b917 100755 --- a/apiserver/import_old_portal.py +++ b/apiserver/import_old_portal.py @@ -19,6 +19,12 @@ MEMBER_FIELDS = [ 'monthly_fees', 'emergency_contact_name', 'emergency_contact_phone', + # minor -> is_minor + 'birthdate', + 'guardian_name', + 'street_address', + # city, provice -> city + 'postal_code', ] TRANSACTION_FIELDS = [ @@ -83,6 +89,10 @@ for o in old: for f in MEMBER_FIELDS: new[f] = o.__dict__.get(f, None) + if o.city and o.province: + new['city'] = '{}, {}'.format(o.city, o.province) + new['is_minor'] = o.minor + small, medium, large = None, None, None if str(o.id) in photo_folders: folder = 'old_photos/' + str(o.id) diff --git a/webclient/src/Account.js b/webclient/src/Account.js index 8dee57a..45a1e8f 100644 --- a/webclient/src/Account.js +++ b/webclient/src/Account.js @@ -1,7 +1,7 @@ import React, { useState, useEffect } from 'react'; import { BrowserRouter as Router, Switch, Route, Link, useParams, useHistory } from 'react-router-dom'; import './light.css'; -import { Container, Divider, Dropdown, Form, Grid, Header, Icon, Image, Menu, Message, Segment, Table } from 'semantic-ui-react'; +import { Container, Checkbox, Divider, Dropdown, Form, Grid, Header, Icon, Image, Menu, Message, Segment, Table } from 'semantic-ui-react'; import { BasicTable, staticUrl, requester } from './utils.js'; import { LoginForm, SignupForm } from './LoginSignup.js'; @@ -63,9 +63,13 @@ function ChangePasswordForm(props) { ); }; -function AccountForm(props) { +export function AccountForm(props) { const member = props.user.member; - const [input, setInput] = useState({ ...member }); + const [input, setInput] = useState({ + ...member, + birthdate: member.birthdate || '', + set_details: true + }); const [error, setError] = useState({}); const [loading, setLoading] = useState(false); const history = useHistory(); @@ -73,6 +77,7 @@ function AccountForm(props) { const handleValues = (e, v) => setInput({ ...input, [v.name]: v.value }); const handleUpload = (e, v) => setInput({ ...input, [v.name]: e.target.files[0] }); const handleChange = (e) => handleValues(e, e.currentTarget); + const handleCheck = (e, v) => setInput({ ...input, [v.name]: v.checked }); const handleSubmit = (e) => { setLoading(true); @@ -113,10 +118,44 @@ function AccountForm(props) { {...makeProps('preferred_name')} /> + + + + + + + + + + + + {input.is_minor && } + {input.is_minor && } + } @@ -125,7 +127,7 @@ function App() {
- {user ? + {user && user.member.set_details ? diff --git a/webclient/src/Home.js b/webclient/src/Home.js index 46e9c60..f903afe 100644 --- a/webclient/src/Home.js +++ b/webclient/src/Home.js @@ -4,64 +4,7 @@ import './light.css'; import { Container, Divider, Dropdown, Form, Grid, Header, Icon, Image, Menu, Message, Segment, Table } from 'semantic-ui-react'; import { BasicTable, staticUrl, requester } from './utils.js'; import { LoginForm, SignupForm } from './LoginSignup.js'; - -function SignupDetailsForm(props) { - const member = props.user.member; - const [input, setInput] = useState({ ...member, set_details: true }); - const [error, setError] = useState({}); - const [loading, setLoading] = useState(false); - - const handleValues = (e, v) => setInput({ ...input, [v.name]: v.value }); - const handleChange = (e) => handleValues(e, e.currentTarget); - - const handleSubmit = (e) => { - setLoading(true); - requester('/members/' + member.id + '/', 'PATCH', props.token, input) - .then(res => { - console.log(res); - setError({}); - props.setUserCache({...props.user, member: res}); - }) - .catch(err => { - setLoading(false); - console.log(err); - setError(err.data); - }); - }; - - const makeProps = (name) => ({ - name: name, - onChange: handleChange, - value: input[name], - error: error[name], - }); - - return ( -
-
Enter Member Details
- - - - - - - Submit - - - ); -}; +import { AccountForm } from './Account.js'; function MemberInfo(props) { const user = props.user; @@ -162,7 +105,7 @@ export function Home(props) { user.member.set_details ? : - + :