import React, { useState, useEffect } from 'react'; import { Link, useParams } from 'react-router-dom'; import './light.css'; import { Button, Checkbox, Dimmer, Form, Message, Header, Icon, Image, Segment, Table } from 'semantic-ui-react'; import moment from 'moment-timezone'; import { statusColor, BasicTable, staticUrl, requester } from './utils.js'; import { TrainingList } from './Training.js'; function AdminCardDetail(props) { const { token, result, card } = props; const [input, setInput] = useState({ ...card }); const [error, setError] = useState(false); const [loading, setLoading] = useState(false); const [success, setSuccess] = useState(false); const id = card.id; 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); setSuccess(false); const data = { ...input, member_id: result.member.id }; requester('/cards/'+id+'/', 'PUT', token, data) .then(res => { setLoading(false); setSuccess(true); setError(false); setInput(res); }) .catch(err => { setLoading(false); console.log(err); setError(err.data); }); }; const makeProps = (name) => ({ name: name, onChange: handleChange, value: input[name] || '', error: error[name], }); const statusOptions = [ { key: '0', text: 'Card Active', value: 'card_active' }, { key: '1', text: 'Card Inactive', value: 'card_inactive' }, ]; return (
{success ? 'Saved.' : 'Save'} Notes: {input.notes || 'None'}
Last Seen:{' '} {input.last_seen ? input.last_seen > '2021-11-14T02:01:35.415685Z' ? moment.utc(input.last_seen).tz('America/Edmonton').format('lll') : moment.utc(input.last_seen).tz('America/Edmonton').format('ll') : 'Unknown' }
); }; let prevAutoscan = ''; export function AdminMemberCards(props) { const { token, result, refreshResult } = props; const cards = result.cards; const startDimmed = Boolean((result.member.paused_date || !result.member.is_allowed_entry || !result.member.vetted_date) && cards.length); const [dimmed, setDimmed] = useState(startDimmed); const [input, setInput] = useState({ active_status: 'card_active' }); const [error, setError] = useState(false); const [loading, setLoading] = useState(false); const [success, setSuccess] = useState(false); const [cardPhoto, setCardPhoto] = useState(false); const { id } = useParams(); useEffect(() => { const startDimmed = Boolean((result.member.paused_date || !result.member.is_allowed_entry || !result.member.vetted_date) && cards.length); setDimmed(startDimmed); }, [result.member]); const handleValues = (e, v) => setInput({ ...input, [v.name]: v.value }); const handleChange = (e) => handleValues(e, e.currentTarget); const handleCheck = (e, v) => setInput({ ...input, [v.name]: v.checked }); const handleSubmit = (e) => { if (loading) return; setLoading(true); setSuccess(false); const data = { ...input, member_id: result.member.id }; requester('/cards/', 'POST', token, data) .then(res => { setLoading(false); setSuccess(true); setError(false); refreshResult(); }) .catch(err => { setLoading(false); console.log(err); setError(err.data); }); }; const getAutoscan = () => { return requester('/stats/', 'GET', token) .then(res => { return res?.autoscan; }) .catch(err => { console.log(err); }); }; const checkAutoscan = () => { getAutoscan().then(newScan => { if (newScan !== prevAutoscan) { prevAutoscan = newScan; setInput({ ...input, card_number: newScan }); } }); }; useEffect(() => { if (cardPhoto) { getAutoscan().then(scan => { prevAutoscan = scan; }); const interval = setInterval(checkAutoscan, 1000); return () => clearInterval(interval); } }, [cardPhoto]); const getCardPhoto = (e) => { e.preventDefault(); requester('/members/' + id + '/card_photo/', 'GET', token) .then(res => res.blob()) .then(res => { setCardPhoto(URL.createObjectURL(res)); }) .catch(err => { console.log(err); }); }; const makeProps = (name) => ({ name: name, onChange: handleChange, value: input[name] || '', error: error[name], }); const statusOptions = [ { key: '0', text: 'Card Active', value: 'card_active' }, { key: '1', text: 'Card Blocked', value: 'card_blocked' }, { key: '2', text: 'Card Inactive', value: 'card_inactive' }, { key: '3', text: 'Card Member Blocked', value: 'card_member_blocked' }, ]; return (
Edit Member Cards
Add a Card
{result.member.photo_large ?

: Member photo missing!

Have the member upload a photo, then refresh this page.

} {cardPhoto &&

How to Add a Card
  1. Right click on image > Save image as...
  2. Right click on file > Print
  3. Select Datacard Printer, Print
  4. Plug card scanner in
  5. Open "RfidReader" on desktop
  6. Scan card, add the number
  7. Have them test their card
Submit {success &&
Success!
} }
Current Cards
{cards.length ? cards.map(x => ) :

None

}

Member paused, unvetted or not allowed entry. {cards.length} card{cards.length === 1 ? '' : 's'} ignored anyway.

); }; export function AdminMemberPause(props) { const { token, result, refreshResult } = props; const [error, setError] = useState(false); const [loading, setLoading] = useState(false); const [success, setSuccess] = useState(false); const [told1, setTold1] = useState(false); const [told2, setTold2] = useState(false); const { id } = useParams(); useEffect(() => { setLoading(false); }, [result.member]); const handlePause = (e) => { if (loading) return; setLoading(true); setSuccess(false); requester('/members/' + id + '/pause/', 'POST', token, {}) .then(res => { setSuccess(true); setError(false); refreshResult(); }) .catch(err => { setLoading(false); console.log(err); setError(true); }); setTold1(false); setTold2(false); }; const handleUnpause = (e) => { if (loading) return; setLoading(true); setSuccess(false); requester('/members/' + id + '/unpause/', 'POST', token, {}) .then(res => { setSuccess(true); setError(false); refreshResult(); }) .catch(err => { setLoading(false); console.log(err); setError(true); }); }; return (
Pause / Unpause Membership

{result.member.paused_date ? result.member.vetted_date && moment().diff(moment(result.member.paused_date), 'days') > 370 ? <>

{result.member.preferred_name} has been away for more than a year and will need to be re-vetted according to our policy.

setTold1(v.checked)} />

setTold2(v.checked)} />

: result.member.status == 'Expired Member' ? <>

{result.member.preferred_name} has expired due to lapse of payment.

setTold1(v.checked)} />

setTold2(v.checked)} />

: : <>

Pause members who are inactive, former, or on vacation.

setTold1(v.checked)} />

setTold2(v.checked)} />

}

{success &&
Success!
} {error &&

Error, something went wrong.

}
); }; export function AdminMemberForm(props) { const { token, result, refreshResult } = props; const [input, setInput] = useState(result.member); const [error, setError] = useState(false); const [loading, setLoading] = useState(false); const [success, setSuccess] = useState(false); const { id } = useParams(); useEffect(() => { setInput(result.member); }, [result.member]); const handleValues = (e, v) => setInput({ ...input, [v.name]: v.value }); const handleChange = (e) => handleValues(e, e.currentTarget); const handleCheck = (e, v) => setInput({ ...input, [v.name]: v.checked }); const handleSubmit = (e) => { if (loading) return; setLoading(true); setSuccess(false); const data = { ...input, email: input.email.toLowerCase() }; requester('/members/' + id + '/', 'PATCH', token, data) .then(res => { setLoading(false); setSuccess(true); setError(false); refreshResult(); }) .catch(err => { setLoading(false); console.log(err); setError(err.data); }); }; const makeProps = (name) => ({ name: name, onChange: handleChange, value: input[name] || '', error: error[name], }); return (
Edit Member Details
Submit {success &&
Success!
}
); }; export function AdminMemberInfo(props) { const member = props.result.member; return (
Admin Details
Status: {member.status || 'Unknown'} Protocoin: ₱ {member.protocoin.toFixed(2)} Application Date: {member.application_date} Expire Date: {member.expire_date} {member.paused_date && Paused Date: {member.paused_date} } Phone: {member.phone} Emergency Contact Name: {member.emergency_contact_name || 'None'} Emergency Contact Phone: {member.emergency_contact_phone || 'None'} Discourse Username: {member.discourse_username ? {member.discourse_username} : 'None' } Public Bio:

{member.public_bio || 'None yet.'}

{member.member_forms &&

View application forms

}
); }; export function AdminMemberTraining(props) { const training = props.result.training; return (
Member Training
{training.length ? :

None

}
); }; export function AdminCert(props) { const { token, result, name, field, refreshResult, loading, setLoading } = props; const member = result.member; const handleCert = (e) => { e.preventDefault(); if (loading) return; setLoading(true); let data = Object(); data[field] = moment.utc().tz('America/Edmonton').format('YYYY-MM-DD'); requester('/members/' + member.id + '/', 'PATCH', token, data) .then(res => { refreshResult(); }) .catch(err => { console.log(err); }); }; const handleUncert = (e) => { e.preventDefault(); if (loading) return; setLoading(true); let data = Object(); data[field] = null; requester('/members/' + member.id + '/', 'PATCH', token, data) .then(res => { refreshResult(); }) .catch(err => { console.log(err); }); }; useEffect(() => { setLoading(false); }, [member[field]]); return ( member[field] ? : ); } export function AdminMemberCertifications(props) { const member = props.result.member; const [loading, setLoading] = useState(false); return (
Machine Access

These control access to the lockouts.

Name Enabled Course Common {member.vetted_date || member.orientation_date ? 'Yes' : 'No'} New Members: Orientation and Basic Safety SawStop {member.wood_cert_date ? 'Yes, ' + member.wood_cert_date : 'No'} SawStop course (WIP) Drum Sander {member.wood2_cert_date ? 'Yes, ' + member.wood2_cert_date : 'No'} Woodworking Tools 2: Jointer, Thickness Planer, Drum Sander {false && Lathe {member.lathe_cert_date ? 'Yes, ' + member.lathe_cert_date : 'No'} Metal: Metal Cutting & Manual Lathe } {false && Mill {member.mill_cert_date ? 'Yes, ' + member.mill_cert_date : 'No'} Metal: Manual Mill & Advanced Lathe } Tormach CNC {member.tormach_cnc_cert_date ? 'Yes, ' + member.tormach_cnc_cert_date : 'No'} Tormach: CAM and Tormach Intro Precix CNC {member.precix_cnc_cert_date ? 'Yes, ' + member.precix_cnc_cert_date : 'No'} Basic CNC Wood Router Rabbit Laser {member.rabbit_cert_date ? 'Yes, ' + member.rabbit_cert_date : 'No'} Laser: Cutting and Engraving Trotec Laser {member.trotec_cert_date ? 'Yes, ' + member.trotec_cert_date : 'No'} Laser: Trotec Course
); };