Add API and UI to claim a member shelf

This commit is contained in:
Tanner Collin 2023-05-30 23:44:05 +00:00
parent 9ec850abfe
commit 9d6c2f8bb8
4 changed files with 114 additions and 2 deletions

View File

@ -1790,6 +1790,35 @@ class StorageSpaceViewSet(Base, List, Retrieve, Update):
queryset = models.StorageSpace.objects.all().order_by('id') queryset = models.StorageSpace.objects.all().order_by('id')
serializer_class = serializers.StorageSpaceSerializer serializer_class = serializers.StorageSpaceSerializer
@action(detail=False, methods=['post'], permission_classes=[AllowMetadata | IsAuthenticated])
def claim(self, request):
user = self.request.user
if user.storage.count():
raise exceptions.ValidationError(dict(shelf_id='You already have a shelf.'))
try:
shelf_id = str(request.data['shelf_id']).upper()
except KeyError:
raise exceptions.ValidationError(dict(shelf_id='This field is required.'))
try:
storage = models.StorageSpace.objects.get(shelf_id=shelf_id)
except models.StorageSpace.DoesNotExist:
raise exceptions.ValidationError(dict(shelf_id='Shelf ID not found.'))
if storage.location != 'member_shelves':
raise exceptions.ValidationError(dict(shelf_id='Not a member shelf. Please see a Director.'))
if storage.user:
owner = storage.user.member.preferred_name
raise exceptions.ValidationError(dict(shelf_id='Shelf already belongs to {}.'.format(owner)))
storage.user = user
storage.save()
return Response(200)
class RegistrationView(RegisterView): class RegistrationView(RegisterView):
serializer_class = serializers.MyRegisterSerializer serializer_class = serializers.MyRegisterSerializer

View File

@ -27,7 +27,7 @@ import { Subscribe } from './PayPal.js';
import { PasswordReset, ConfirmReset } from './PasswordReset.js'; import { PasswordReset, ConfirmReset } from './PasswordReset.js';
import { NotFound, PleaseLogin } from './Misc.js'; import { NotFound, PleaseLogin } from './Misc.js';
import { Debug } from './Debug.js'; import { Debug } from './Debug.js';
import { StorageDetail } from './Storage.js'; import { StorageDetail, ClaimShelf } from './Storage.js';
import { Garden } from './Garden.js'; import { Garden } from './Garden.js';
import { Footer } from './Footer.js'; import { Footer } from './Footer.js';
import { LCARS1Display, LCARS2Display } from './Display.js'; import { LCARS1Display, LCARS2Display } from './Display.js';
@ -285,6 +285,10 @@ function App() {
{user && user.member.set_details ? {user && user.member.set_details ?
<Switch> <Switch>
<Route path='/claimshelf'>
<ClaimShelf token={token} user={user} refreshUser={refreshUser} />
</Route>
<Route path='/account'> <Route path='/account'>
<Account token={token} user={user} refreshUser={refreshUser} /> <Account token={token} user={user} refreshUser={refreshUser} />
</Route> </Route>

View File

@ -77,7 +77,7 @@ function MemberInfo(props) {
</Button> </Button>
) )
: :
'None' <>None <Link to='/claimshelf'>[claim]</Link></>
} }
</Table.Cell> </Table.Cell>
</Table.Row> </Table.Row>

View File

@ -241,3 +241,82 @@ export function StorageList(props) {
</div> </div>
); );
}; };
export function ClaimShelfForm(props) {
const { token, user, refreshUser } = props;
const member = user.member;
const [input, setInput] = useState({});
const [error, setError] = useState({});
const [loading, setLoading] = useState(false);
const history = useHistory();
const handleValues = (e, v) => setInput({ ...input, [v.name]: v.value });
const handleChange = (e) => handleValues(e, e.currentTarget);
const handleSubmit = (e) => {
if (loading) return;
setLoading(true);
requester('/storage/claim/', 'POST', token, input)
.then(res => {
setError({});
refreshUser();
history.push('/');
})
.catch(err => {
setLoading(false);
console.log(err);
setError(err.data);
});
};
const makeProps = (name) => ({
name: name,
onChange: handleChange,
value: input[name] || '',
error: error[name],
});
return (
<Form onSubmit={handleSubmit}>
<div className='field'>
<label>Spaceport Username</label>
<p>{user.username}</p>
</div>
<Form.Input
label='Shelf ID'
autoComplete='off'
required
{...makeProps('shelf_id')}
maxLength={3}
/>
<Form.Button loading={loading} error={error.non_field_errors || error.detail}>
Submit
</Form.Button>
</Form>
);
};
export function ClaimShelf(props) {
const { token, user } = props;
const [error, setError] = useState(false);
return (
<Container>
<Grid stackable columns={2}>
<Grid.Column>
<Header size='large'>Claim Member Shelf</Header>
<p>Use this form to claim a member shelf.</p>
<p>Please make sure your name and contact info are visible on the shelf.</p>
<p>Use the Shelf ID visible on the corner label (A1A, A2B, etc.)</p>
<ClaimShelfForm {...props} />
</Grid.Column>
</Grid>
</Container>
);
};