Make the Class list publicly available, add Class Feed page

This commit is contained in:
Tanner Collin 2022-01-26 04:21:47 +00:00
parent e6aaef9bf1
commit 987e2a7465
3 changed files with 218 additions and 171 deletions

View File

@ -230,7 +230,7 @@ class CardViewSet(Base, Create, Retrieve, Update, Destroy):
class CourseViewSet(Base, List, Retrieve, Create, Update): 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') queryset = models.Course.objects.annotate(date=Max('sessions__datetime')).order_by('-date')
def get_serializer_class(self): def get_serializer_class(self):
@ -241,7 +241,7 @@ class CourseViewSet(Base, List, Retrieve, Create, Update):
class SessionViewSet(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): def get_queryset(self):
if self.action == 'list': if self.action == 'list':

View File

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

View File

@ -50,6 +50,43 @@ function ClassTable(props) {
let classesCache = false; 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) { export function Classes(props) {
const [classes, setClasses] = useState(classesCache); const [classes, setClasses] = useState(classesCache);
const { token } = props; const { token } = props;