Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
f093ac0
Install React, upgrade webpack
schmave May 23, 2024
378b7a9
Set up webpack, etc. for a React-based edit minutes page
schmave May 26, 2024
6886091
Google Java Format
May 26, 2024
ea18c7b
Replace class compoent
angusmccloud May 28, 2024
8160ccc
Missing babel core
angusmccloud May 28, 2024
a8b6360
Grab reference data as passed from parent app
angusmccloud May 28, 2024
f5d230e
Moved initialData to State (more things than would be needed)
angusmccloud May 28, 2024
db4167d
Moved react content to its own folder, enabled multiple React routes …
angusmccloud May 28, 2024
e777065
Code Cleanup
angusmccloud May 28, 2024
b02f425
Merged in Main
angusmccloud Sep 21, 2025
63ef9fe
Merged with Main
angusmccloud Sep 21, 2025
10c4c60
Cleanup of Webpack
angusmccloud Sep 21, 2025
3c5e4d9
Fixed issues with webpack not seeing React files
angusmccloud Sep 21, 2025
73c7b90
Safed as window.initialData
angusmccloud Sep 21, 2025
348b6e5
Updated webpack config and script injection so React changes refresh …
angusmccloud Sep 21, 2025
c07850f
Merged in Main
angusmccloud Sep 29, 2025
ef57b35
Reorganized Components
angusmccloud Oct 5, 2025
82a4e7d
Functioning edit minutes page. Needs a cleaner autocomplete formatting
angusmccloud Oct 5, 2025
7830c20
Read minutes works, but need better formatting...
angusmccloud Oct 6, 2025
a044189
Cleaned up components
angusmccloud Oct 10, 2025
824d2ab
JC Code Cleanup
angusmccloud Oct 10, 2025
c96fb86
Style and CSS loaders for raw CSS files
angusmccloud Oct 10, 2025
4f3dafe
Text size cleanup
angusmccloud Oct 10, 2025
3f04042
Style consolidate for Boxes/Cards
angusmccloud Oct 11, 2025
3878115
Lots of formatting cleanup
angusmccloud Oct 11, 2025
9151f35
Fixed deleting cases
angusmccloud Oct 11, 2025
dc306fa
Formatting Cleanup
angusmccloud Oct 11, 2025
72334cf
Merge remote-tracking branch 'origin/main' into reactUpdates
schmave Oct 13, 2025
2f7e927
Merge remote-tracking branch 'origin/main' into reactUpdates
schmave Oct 13, 2025
43371d4
Hid the two react pages from the site's navigation
angusmccloud Oct 22, 2025
33e874a
Basics of Sign In Sheet
angusmccloud Nov 9, 2025
460db1f
Fully functioning react page and PDF export
angusmccloud Nov 9, 2025
84af723
Updated code formatting
angusmccloud Nov 9, 2025
40ee462
Showing same blank-rows in preview as PDF
angusmccloud Nov 10, 2025
5dca9cc
Merge branch 'tcsMVP' into PrintSignInPage
schmave Nov 13, 2025
ad8b4e3
Google Java Format
Nov 13, 2025
3f839fa
Remove minutes stuff
schmave Nov 13, 2025
8c2380f
Revert some changes to npm packages
schmave Nov 13, 2025
df271d2
Merge branch 'main' into only-print-sign-in-page
schmave Nov 13, 2025
8a19ead
Merge remote-tracking branch 'origin/main' into only-print-sign-in-page
schmave Nov 24, 2025
32b90f0
Combine react_app and custodia
schmave Nov 24, 2025
9575b64
Fix fonts in local development, fix eslint package warnings
schmave Nov 24, 2025
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
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"root": true,
"env": {
"browser": true,
"commonjs": true,
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ metals.sbt
.classpath
.project

custodia/stats.html
react/stats.html
3 changes: 3 additions & 0 deletions app/views/main.scala.html
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ <h3>Thanks for your feedback!</h3>
<a @if(selectedBtn.equals("attendance_rules")) { class="active" }
href="@routes.Attendance.rules()">Rules
</a>
<a @if(selectedBtn.equals("sign_in_sheet")) { class="active" }
href="/attendance/signInSheet">Sign In Sheet
</a>
@if(Utils.getOrgConfig(request).org.getAttendanceEnableOffCampus()) {
<a @if(selectedBtn.equals("off_campus_time")) { class="active" }
href="@routes.Attendance.offCampusTime()">Off campus time
Expand Down
6 changes: 3 additions & 3 deletions build_and_copy_to_server.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ npm install
rsync -v -h --progress target/universal/demschooltools-1.1.zip evan@demschooltools.com:/home/evan/


## Custodia & Django stuff
(cd custodia && npm install && npm run compile)
## React & Django stuff
(cd react && npm install && npm run build)

# -r is necessary here because ls-tree includes some symbolic link directories
# and we want to include the files that are contained in them.
git ls-tree -r --name-only head django | xargs zip -r django

# These files are generated by Custodia's build process and not in git
# These files are generated by vite's build process and not in git
zip -r django django/static-vite/

rsync -v -h --progress django.zip evan@demschooltools.com:/home/evan/
Expand Down
6 changes: 4 additions & 2 deletions conf/base.conf
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ play.i18n.langs = [ "en", "en-TRVS" ]
# ~~~~~
db.default.pool = "hikaricp"
db.default.hikaricp.maximumPoolSize = 4
db.default.driver=org.postgresql.Driver
db.default.url="jdbc:postgresql://localhost:5432/school_crm?user=postgres&password=123"
db.default.driver = org.postgresql.Driver
db.default.url = "jdbc:postgresql://127.0.0.1:5432/school_crm"
db.default.username = "postgres"
db.default.password = "123"

# Ebean configuration
# ~~~~~
Expand Down
3 changes: 3 additions & 0 deletions conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ GET /attendance/jsonPeople controllers.Attendance.jsonPeople(t
GET /attendance/viewWeek controllers.Attendance.viewWeek(date : String ?= "", request: Request)
GET /attendance/editWeek controllers.Attendance.editWeek(date : String ?= "", request: Request)

GET /attendance/signInSheet controllers.Proxy.proxy0(request: Request)
GET /attendance/signInSheet/*extra controllers.Proxy.proxy(request: Request, extra: String)

GET /attendance/checkin controllers.Public.checkin()
GET /attendance/checkin/data controllers.Checkin.checkinData(time: String, request: Request)
POST /attendance/checkin/message controllers.Checkin.checkinMessage(time_string: String, personId: Integer, is_arriving: Boolean, request: Request)
Expand Down
2 changes: 1 addition & 1 deletion django/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
static-vite/
dev-static-root/
dev-static-root/
2 changes: 1 addition & 1 deletion django/Procfile
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
django: uv run manage.py migrate && uv run manage.py runserver
custodia: cd ../custodia && npm install && npm run watch
react: cd ../react && npm install && npm run watch
2 changes: 1 addition & 1 deletion django/custodia/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

{% vite_hmr_client %}
{% vite_react_refresh %}
{% vite_asset 'src/js/app.jsx' %}
{% vite_asset 'custodia/js/app.jsx' %}
</head>
<body>
{% csrf_token %}
Expand Down
2 changes: 1 addition & 1 deletion django/custodia/templates/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

{% vite_hmr_client %}
{% vite_react_refresh %}
{% vite_asset 'src/js/cssonly.js' %}
{% vite_asset 'custodia/js/cssonly.js' %}
</head>
<body>
<nav class="navbar" role="navigation">
Expand Down
3 changes: 3 additions & 0 deletions django/demschooltools/templates/main.html
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ <h3>Thanks for your feedback!</h3>
<a {% if selectedBtn == "attendance_rules" %}class="active"{% endif %}
href="/attendance/rules">Rules
</a>
<a {% if selectedBtn == "sign_in_sheet" %}class="active"{% endif %}
href="/attendance/signInSheet">Sign In Sheet
</a>
{% if org_config.org.attendance_enable_off_campus %}
<a {% if selectedBtn == "off_campus_time" %}class="active"{% endif %}
href="/attendance/offCampusTime">Off campus time
Expand Down
2 changes: 2 additions & 0 deletions django/demschooltools/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
StudentsTodayView,
SwipeView,
)
from dst.attendance_views import SignInSheetView
from dst.manual_views import (
CreateUpdateChapter,
CreateUpdateEntry,
Expand Down Expand Up @@ -86,6 +87,7 @@ def to_url(self, value):
"custodia-api",
),
),
path("attendance/signInSheet", SignInSheetView.as_view()),
path("viewManual", view_manual),
path("viewManualChanges", view_manual_changes),
path("searchManual", search_manual),
Expand Down
79 changes: 79 additions & 0 deletions django/dst/attendance_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import json

from django.contrib.auth.mixins import LoginRequiredMixin
from django.template.loader import render_to_string
from django.views import View

from dst.models import Person, Tag, UserRole
from dst.utils import DstHttpRequest, render_main_template


class SignInSheetView(LoginRequiredMixin, View):
def get(self, request: DstHttpRequest):
if not request.user.hasRole(UserRole.ATTENDANCE):
raise PermissionError("You don't have privileges to access this item")

org = request.org

# Get people with attendance tags (with their tags)
people_with_tags = []
for person in (
Person.objects.filter(
tags__show_in_attendance=True,
tags__organization=org,
)
.distinct()
.prefetch_related("tags")
.order_by("display_name", "first_name")
):
people_with_tags.append(
{
"id": person.id,
"label": person.get_name() + " " + person.last_name,
"tags": [tag.id for tag in person.tags.all()],
}
)

# Get attendance tags
tags = []
for tag in Tag.objects.filter(
organization=org, show_in_attendance=True
).order_by("title"):
tags.append(
{
"id": tag.id,
"label": tag.title,
}
)

# Get all people (for guest selection)
all_people = []
for person in (
Person.objects.filter(organization=org, is_family=False)
.exclude(first_name="", last_name="", display_name="")
.only("display_name", "first_name", "last_name")
.distinct()
):
all_people.append(
{
"id": person.id,
"label": person.get_name() + " " + person.last_name,
}
)
all_people.sort(key=lambda x: x["label"])

return render_main_template(
request,
"attendance",
render_to_string(
"sign_in_sheet.html",
{
"people_json": json.dumps(people_with_tags),
"tags_json": json.dumps(tags),
"all_people_json": json.dumps(all_people),
"request": request,
},
),
"Sign in sheet",
"sign_in_sheet",
)
7 changes: 2 additions & 5 deletions django/dst/manual_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from django.db.models.functions import Concat
from django.db.transaction import atomic
from django.forms import Form, ModelForm, TextInput, ValidationError
from django.http import HttpRequest, HttpResponseNotFound
from django.http import HttpResponseNotFound
from django.http.response import HttpResponse as HttpResponse
from django.shortcuts import redirect, render
from django.template.loader import render_to_string
Expand All @@ -33,16 +33,13 @@
create_pdf_response,
render_html_to_pdf,
)
from dst.utils import DstHttpRequest


def login_required():
return django_login_required(login_url="/login")


class DstHttpRequest(HttpRequest):
org: Organization


def render_main_template(
request: DstHttpRequest,
content: str,
Expand Down
14 changes: 14 additions & 0 deletions django/dst/templates/sign_in_sheet.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{% load django_vite %}

<div id="react-root"></div>

<script type="text/javascript">
window.initialData = window.initialData || {};
window.initialData.people = {{ people_json|safe }};
window.initialData.tags = {{ tags_json|safe }};
window.initialData.allPeople = {{ all_people_json|safe }};
</script>

{% vite_hmr_client %}
{% vite_react_refresh %}
{% vite_asset 'index.jsx' %}
File renamed without changes.
73 changes: 73 additions & 0 deletions react/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React, { useState } from 'react';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import { ThemeProvider } from '@mui/material/styles';
import { Snackbar, Alert } from '@mui/material';
import { SnackbarContext, DefaultSnackbar } from './contexts';
import { lightTheme } from './theme/theme';

import '@fontsource/roboto/300.css';
import '@fontsource/roboto/400.css';
import '@fontsource/roboto/500.css';
import '@fontsource/roboto/700.css';

import SignInSheetPage from './pages/SignInSheetPage/SignInSheetPage';

// We're not controlling routing with React, but this lets us use one React App
// and map the Play/Scala paths to React Pages
const router = createBrowserRouter([
{ path: '/attendance/signInSheet', element: <SignInSheetPage /> },
]);

function App() {
const [showSnackbar, setShowSnackbar] = useState(false);
const [snackbarDetails, setSnackbarDetails] = useState(DefaultSnackbar);

// Pieces for the Snackbar Context
const setSnackbar = (props) => {
const {
message,
action,
severity = 'success',
duration = 5000,
} = props;
setSnackbarDetails({
message,
duration,
action,
severity,
});
setShowSnackbar(true);
};

const onDismissSnackBar = () => {
setShowSnackbar(false);
setSnackbarDetails(DefaultSnackbar);
};

return (
<ThemeProvider theme={lightTheme}>
<SnackbarContext.Provider
value={{ snackbar: snackbarDetails, setSnackbar }}
>
<RouterProvider router={router} />
<Snackbar
open={showSnackbar}
onClose={onDismissSnackBar}
message={snackbarDetails.message}
action={snackbarDetails.action}
autoHideDuration={snackbarDetails.duration}
>
<Alert
onClose={onDismissSnackBar}
severity={snackbarDetails.severity}
sx={{ width: '100%' }}
>
{snackbarDetails.message}
</Alert>
</Snackbar>
</SnackbarContext.Provider>
</ThemeProvider>
);
}

export default App;
File renamed without changes.
File renamed without changes.
Loading