Make the Class list publicly available, add Class Feed page

master
Tanner Collin 2 years ago
parent e6aaef9bf1
commit 987e2a7465
  1. 4
      apiserver/apiserver/api/views.py
  2. 364
      webclient/src/App.js
  3. 37
      webclient/src/Classes.js

@ -230,7 +230,7 @@ class CardViewSet(Base, Create, Retrieve, Update, Destroy):
class CourseViewSet(Base, List, Retrieve, Create, Update):
permission_classes = [AllowMetadata | IsAuthenticated, IsAdminOrReadOnly | IsInstructorOrReadOnly]
permission_classes = [AllowMetadata | IsAuthenticatedOrReadOnly, IsAdminOrReadOnly | IsInstructorOrReadOnly]
queryset = models.Course.objects.annotate(date=Max('sessions__datetime')).order_by('-date')
def get_serializer_class(self):
@ -241,7 +241,7 @@ class CourseViewSet(Base, List, Retrieve, Create, Update):
class SessionViewSet(Base, List, Retrieve, Create, Update):
permission_classes = [AllowMetadata | IsAuthenticated, IsAdminOrReadOnly | IsInstructorOrReadOnly]
permission_classes = [AllowMetadata | IsAuthenticatedOrReadOnly, IsAdminOrReadOnly | IsInstructorOrReadOnly]
def get_queryset(self):
if self.action == 'list':

@ -18,7 +18,7 @@ import { Admin } from './Admin.js';
import { Paste } from './Paste.js';
import { Sign } from './Sign.js';
import { Courses, CourseDetail } from './Courses.js';
import { Classes, ClassDetail } from './Classes.js';
import { ClassFeed, Classes, ClassDetail } from './Classes.js';
import { Members, MemberDetail } from './Members.js';
import { Charts } from './Charts.js';
import { Auth } from './Auth.js';
@ -112,206 +112,216 @@ function App() {
<div className='content-wrap'>
<div className='content-wrap-inside'>
<Container>
<div className='hero'>
<Link to='/'>
<img src='/logo-long.svg' className='logo-long' />
</Link>
</div>
{window.location.hostname !== 'my.protospace.ca' &&
<p style={{ background: 'yellow' }}>~~~~~ Development site ~~~~~</p>
}
</Container>
<Menu>
<Container>
<Menu.Item
content='Home'
as={Link}
to='/'
/>
<Dropdown item text='Member' id='ps-menu'>
<Dropdown.Menu>
<Dropdown.Item
content='Account'
as={Link}
to='/account'
/>
<Dropdown.Item
content='Transactions'
as={Link}
to='/transactions'
/>
<Dropdown.Item
content='Paymaster'
<Switch>
<Route exact path='/classfeed'>
<ClassFeed />
</Route>
<Route path='/'>
<Container>
<div className='hero'>
<Link to='/'>
<img src='/logo-long.svg' className='logo-long' />
</Link>
</div>
{window.location.hostname !== 'my.protospace.ca' &&
<p style={{ background: 'yellow' }}>~~~~~ Development site ~~~~~</p>
}
</Container>
<Menu>
<Container>
<Menu.Item
content='Home'
as={Link}
to='/paymaster'
to='/'
/>
<Dropdown.Item
content='Training'
as={Link}
to='/training'
/>
<Dropdown.Item
content='Cards / Access'
as={Link}
to='/cards'
/>
</Dropdown.Menu>
</Dropdown>
<Dropdown item text='Space' id='ps-menu'>
<Dropdown.Menu>
<Dropdown.Item
content='Member List'
as={Link}
to='/members'
/>
<Dropdown.Item
content='Classes'
as={Link}
to='/classes'
/>
<Dropdown.Item
content='Utilities'
as={Link}
to='/utils'
/>
<Dropdown.Item
content='Charts'
as={Link}
to='/charts'
/>
{user && isAdmin(user) && <Dropdown.Item
content='Admin'
as={Link}
to='/admin'
/>}
{user && isAdmin(user) && <Dropdown.Item
content='Transactions'
as={Link}
to='/admintrans'
/>}
</Dropdown.Menu>
</Dropdown>
{user && <Menu.Menu position='right'>
<Menu.Item
content={yousure ? 'You Sure?' : 'Log Out'}
onClick={logout}
icon='cancel'
/>
<Menu.Item fitted content='' />
</Menu.Menu>}
</Container>
</Menu>
<Route exact path='/'>
<Home token={token} setTokenCache={setTokenCache} user={user} refreshUser={refreshUser} />
</Route>
<div className='topPadding'>
<Switch>
<Route path='/password/reset/confirm/:uid/:token'>
<ConfirmReset />
</Route>
<Route path='/password/reset'>
<PasswordReset />
</Route>
<Route path='/utils'>
<Paste token={token} />
</Route>
<Route path='/sign'>
<Sign token={token} />
</Route>
<Route path='/charts'>
<Charts />
<Dropdown item text='Member' id='ps-menu'>
<Dropdown.Menu>
<Dropdown.Item
content='Account'
as={Link}
to='/account'
/>
<Dropdown.Item
content='Transactions'
as={Link}
to='/transactions'
/>
<Dropdown.Item
content='Paymaster'
as={Link}
to='/paymaster'
/>
<Dropdown.Item
content='Training'
as={Link}
to='/training'
/>
<Dropdown.Item
content='Cards / Access'
as={Link}
to='/cards'
/>
</Dropdown.Menu>
</Dropdown>
<Dropdown item text='Space' id='ps-menu'>
<Dropdown.Menu>
<Dropdown.Item
content='Member List'
as={Link}
to='/members'
/>
<Dropdown.Item
content='Classes'
as={Link}
to='/classes'
/>
<Dropdown.Item
content='Utilities'
as={Link}
to='/utils'
/>
<Dropdown.Item
content='Charts'
as={Link}
to='/charts'
/>
{user && isAdmin(user) && <Dropdown.Item
content='Admin'
as={Link}
to='/admin'
/>}
{user && isAdmin(user) && <Dropdown.Item
content='Transactions'
as={Link}
to='/admintrans'
/>}
</Dropdown.Menu>
</Dropdown>
{user && <Menu.Menu position='right'>
<Menu.Item
content={yousure ? 'You Sure?' : 'Log Out'}
onClick={logout}
icon='cancel'
/>
<Menu.Item fitted content='' />
</Menu.Menu>}
</Container>
</Menu>
<Route exact path='/'>
<Home token={token} setTokenCache={setTokenCache} user={user} refreshUser={refreshUser} />
</Route>
<Route path='/auth'>
<Auth user={user} />
</Route>
<Route path='/subscribe'>
<Subscribe />
</Route>
{user && user.member.set_details ?
<div className='topPadding'>
<Switch>
<Route path='/account'>
<Account token={token} user={user} refreshUser={refreshUser} />
</Route>
<Route path='/transactions/:id'>
<TransactionDetail token={token} user={user} refreshUser={refreshUser} />
<Route path='/password/reset/confirm/:uid/:token'>
<ConfirmReset />
</Route>
<Route path='/transactions'>
<Transactions user={user} />
<Route path='/password/reset'>
<PasswordReset />
</Route>
<Route path='/paymaster'>
<Paymaster user={user} />
<Route path='/utils'>
<Paste token={token} />
</Route>
<Route path='/cards'>
<Cards token={token} user={user} />
<Route path='/sign'>
<Sign token={token} />
</Route>
<Route path='/training'>
<Training user={user} />
<Route path='/charts'>
<Charts />
</Route>
<Route path='/courses/:id'>
<CourseDetail token={token} user={user} />
</Route>
<Route path='/courses'>
<Courses token={token} user={user} />
<Route path='/auth'>
<Auth user={user} />
</Route>
<Route path='/classes/:id'>
<ClassDetail token={token} user={user} refreshUser={refreshUser} />
</Route>
<Route path='/classes'>
<Classes token={token} />
<Route path='/subscribe'>
<Subscribe />
</Route>
<Route path='/members/:id'>
<MemberDetail token={token} user={user} />
</Route>
<Route path='/members'>
<Members token={token} user={user} />
<Route exact path='/classes'>
<Classes token={token} />
</Route>
{user && isAdmin(user) &&
<Route path='/admin'>
<Admin token={token} user={user} />
{user && user.member.set_details ?
<Switch>
<Route path='/account'>
<Account token={token} user={user} refreshUser={refreshUser} />
</Route>
<Route path='/transactions/:id'>
<TransactionDetail token={token} user={user} refreshUser={refreshUser} />
</Route>
<Route path='/transactions'>
<Transactions user={user} />
</Route>
<Route path='/paymaster'>
<Paymaster user={user} />
</Route>
<Route path='/cards'>
<Cards token={token} user={user} />
</Route>
<Route path='/training'>
<Training user={user} />
</Route>
<Route path='/courses/:id'>
<CourseDetail token={token} user={user} />
</Route>
<Route path='/courses'>
<Courses token={token} user={user} />
</Route>
<Route path='/classes/:id'>
<ClassDetail token={token} user={user} refreshUser={refreshUser} />
</Route>
<Route path='/members/:id'>
<MemberDetail token={token} user={user} />
</Route>
<Route path='/members'>
<Members token={token} user={user} />
</Route>
{user && isAdmin(user) &&
<Route path='/admin'>
<Admin token={token} user={user} />
</Route>
}
{user && isAdmin(user) &&
<Route path='/admintrans'>
<AdminTransactions token={token} user={user} />
</Route>
}
<Route path='/:page'>
<NotFound />
</Route>
</Switch>
:
<Route path='/:page'>
<PleaseLogin />
</Route>
}
{user && isAdmin(user) &&
<Route path='/admintrans'>
<AdminTransactions token={token} user={user} />
</Route>
}
<Route path='/:page'>
<NotFound />
</Route>
</Switch>
:
<Route path='/:page'>
<PleaseLogin />
</Route>
}
</Switch>
</div>
</div>
</Route>
</Switch>
</div>
</div>

@ -50,6 +50,43 @@ function ClassTable(props) {
let classesCache = false;
export function ClassFeed(props) {
const [classes, setClasses] = useState(classesCache);
useEffect(() => {
const get = async() => {
requester('/sessions/', 'GET', '')
.then(res => {
setClasses(res.results);
classesCache = res.results;
})
.catch(err => {
console.log(err);
});
};
get();
const interval = setInterval(get, 60000);
return () => clearInterval(interval);
}, []);
const now = new Date().toISOString();
return (
<Container>
<p/>
<Header size='large'>Upcoming Protospace Classes</Header>
{classes ?
<ClassTable classes={classes.filter(x => x.datetime > now).sort((a, b) => a.datetime > b.datetime ? 1 : -1)} />
:
<p>Loading...</p>
}
</Container>
);
};
export function Classes(props) {
const [classes, setClasses] = useState(classesCache);
const { token } = props;

Loading…
Cancel
Save