Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Getting Started with Create React App
# Education Assignment Workflow (React sample)

This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
This repository is an education-oriented sample app that demonstrates an end-to-end assignment and review workflow using an in‑viewer PDF editor and form fields. It was bootstrapped with Create React App and uses a lightweight, file-backed viewer integration and small local stores to simulate instructors, learners, and staff interactions.

## Available Scripts

Expand Down Expand Up @@ -68,3 +68,32 @@ This section has moved here: [https://facebook.github.io/create-react-app/docs/d
### `npm run build` fails to minify

This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)

Login (demo credentials)

The app uses a small demo authentication flow with seeded users stored in `localStorage` under the key `demo_users`.

Use these credentials on the Login page:

- Staff (teacher)
- Username: John
- Password: password
- Role: Staff

- Learners (students)
- Username: Alice
- Password: password
- Role: Student
- Username: Simon
- Password: password
- Role: Student
- Username: Clara
- Password: password
- Role: Student

To reset the seeded users, clear `localStorage` key `demo_users` or open the browser devtools and run:

```js
localStorage.removeItem('demo_users')
```
Then reload the app — the sample will re-seed the default demo users.
2 changes: 1 addition & 1 deletion src/AssignmentModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ export default function AssignmentModal({
documentPath={objectSrc}
style={{ width: '100%', height: '100%' }}
enableToolbar={true}
resourceUrl={'https://cdn.syncfusion.com/ej2/23.2.6/dist/ej2-pdfviewer-lib'}
resourceUrl={'https://cdn.syncfusion.com/ej2/33.1.47/dist/ej2-pdfviewer-lib'}
toolbarSettings={{ showTooltip: true }}
resourcesLoaded={handleResourcesLoaded}
>
Expand Down
62 changes: 34 additions & 28 deletions src/StaffMaterials.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -251,35 +251,36 @@ export default function StaffMaterials({ user, onLogout }) {
const MAX_BYTES = 4 * 1024 * 1024; // 4 MB per file

/* ------------------------ Load materials & staff ------------------------ */
useEffect(() => {
let raw = localStorage.getItem(STORAGE_KEY);
if (!raw) {
const old = sessionStorage.getItem(STORAGE_KEY);
if (old) {
try { localStorage.setItem(STORAGE_KEY, old); raw = old; } catch (e) { console.warn('Migration to localStorage failed', e); }
}
}
/* ------------------------ Load materials (SESSION ONLY) ------------------------ */
useEffect(() => {
try {
const raw = sessionStorage.getItem(STORAGE_KEY);
if (raw) {
try {
const parsed = JSON.parse(raw);
const sanitized = parsed.map((p) => {
const copy = { ...p };
if (copy.materialUrl && typeof copy.materialUrl === 'string' && copy.materialUrl.startsWith('blob:')) { copy.materialUrl = null; copy.status = copy.status || 'Needs Reupload'; }
if (copy.assignmentUrl && typeof copy.assignmentUrl === 'string' && copy.assignmentUrl.startsWith('blob:')) { copy.assignmentUrl = null; copy.status = copy.status || 'Needs Reupload'; }
return copy;
});
setMaterials(sanitized);
try { localStorage.setItem(STORAGE_KEY, JSON.stringify(sanitized)); } catch { }
} catch (e) { console.error(e); }
setMaterials(JSON.parse(raw));
} else {
setMaterials([]); // ✅ fresh tab = empty
}
const sn = sessionStorage.getItem(STAFF_KEY) || '';
if (user && user.username) setStaffName(user.username); else setStaffName(sn);
}, [user]);
} catch {
setMaterials([]);
}

// staff name logic unchanged
const sn = sessionStorage.getItem(STAFF_KEY) || '';
if (user && user.username) setStaffName(user.username);
else setStaffName(sn);
}, [user]);

useEffect(() => { sessionStorage.setItem(STAFF_KEY, staffName); }, [staffName]);

const saveMaterialsList = useCallback((list) => {
try { localStorage.setItem(STORAGE_KEY, JSON.stringify(list)); return true; } catch (e) { console.error('Failed to write materials to localStorage', e); return false; }
}, []);
try {
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(list));
return true;
} catch (e) {
console.error('Failed to write materials to sessionStorage', e);
return false;
}
}, []);
function areAllFieldsFilled(fields) {
if (!Array.isArray(fields) || !fields.length) return false;

Expand Down Expand Up @@ -379,8 +380,10 @@ export default function StaffMaterials({ user, onLogout }) {
// Persist list
let existing = [];
try {
const raw = localStorage.getItem(STORAGE_KEY);
existing = raw ? JSON.parse(raw) : [];

const raw = sessionStorage.getItem(STORAGE_KEY);
existing = raw ? JSON.parse(raw) : [];

} catch {
existing = materials || [];
}
Expand Down Expand Up @@ -476,7 +479,10 @@ export default function StaffMaterials({ user, onLogout }) {
const key = `file_${pendingAssignFor.id}_as`; await saveFile(key, file);
const url = `idb:${key}`; const name = file.name;
let current = [];
try { const raw = localStorage.getItem(STORAGE_KEY); current = raw ? JSON.parse(raw) : materials; } catch { current = materials; }
try {
const raw = sessionStorage.getItem(STORAGE_KEY);
current = raw ? JSON.parse(raw) : materials;
} catch { current = materials; }
const updated = current.map((m) => (m.id === pendingAssignFor.id ? { ...m, assignmentUrl: url, assignmentName: name, updatedBy: staffName || (user && (user.username || user.name)) || '' } : m));
const ok = saveMaterialsList(updated); if (ok) setMaterials(updated);
} catch (e2) { console.error('Failed to add assignment', e2); }
Expand Down Expand Up @@ -519,7 +525,7 @@ export default function StaffMaterials({ user, onLogout }) {
*/
function handleUpdateStatus(id, statusOrUpdates) {
let current = [];
try { const raw = localStorage.getItem(STORAGE_KEY); current = raw ? JSON.parse(raw) : []; } catch { current = materials; }
try { const raw = sessionStorage.getItem(STORAGE_KEY); current = raw ? JSON.parse(raw) : []; } catch { current = materials; }

// Helper to map statuses to comments
function mapStatusToComment(st, forUser) {
Expand Down
2 changes: 1 addition & 1 deletion src/ViewerModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -918,7 +918,7 @@ export default function ViewerModal({ open, onClose, item, onUpdateStatus, user,
<PdfViewerComponent
id="ejs-pdf-viewer"
ref={viewerRef}
resourceUrl="https://cdn.syncfusion.com/ej2/23.2.6/dist/ej2-pdfviewer-lib"
resourceUrl="https://cdn.syncfusion.com/ej2/33.1.47/dist/ej2-pdfviewer-lib"
enableToolbar={true}
documentPath={undefined}
documentLoad={onDocumentLoad}
Expand Down