Skip to content

Commit 9a11e60

Browse files
committed
Adding lessons to plans
1 parent 53e0ac2 commit 9a11e60

7 files changed

Lines changed: 470 additions & 75 deletions

File tree

public/css/all.css

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -724,8 +724,10 @@ label .description {
724724

725725
.planItemHeader { background-color:#EEE; border-bottom: 3px solid var(--c1l2); font-weight:bold; padding: 5px 5px 5px 10px; text-transform:uppercase; }
726726
.planItem {border-bottom: 1px solid #DDD; padding: 5px 5px 5px 10px; }
727-
.planItem div:first-of-type { float:left;width:100px }
727+
.planItem > div:first-of-type:not([style*="clear"]) { float:left;width:100px }
728728
.planItemDescription { font-style:italic; color:#777; padding-left:22px;}
729+
.planItemDescription p:first-child { margin-top:0px; margin-bottom: 0px; }
730+
729731

730732
.chordPro H3 { margin-bottom:0px; }
731733
.chordPro .line { margin-top:5px; vertical-align: bottom;}

src/helpers/EnvironmentHelper.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,12 @@ export class EnvironmentHelper {
8383
await Locale.init([`/locales/{{lng}}.json?v=1`, `/apphelper/locales/{{lng}}.json`]);
8484
};
8585

86-
static initLocal = async () => {};
86+
static initLocal = async () => { };
8787

8888
static initDev = () => {
8989
this.initStaging();
90-
EnvironmentHelper.LessonsApi = process.env.NEXT_PUBLIC_LESSONS_API || EnvironmentHelper.LessonsApi;
90+
EnvironmentHelper.LessonsApi = process.env.REACT_APP_LESSONS_API || EnvironmentHelper.LessonsApi;
91+
console.log("LessonsAPI is", EnvironmentHelper.LessonsApi, process.env.REACT_APP_LESSONS_API);
9192
};
9293

9394
//NOTE: None of these values are secret.

src/helpers/Interfaces.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export interface PlanItemInterface {
6262
label?: string;
6363
description?: string;
6464
seconds?: number;
65+
link?: string;
6566

6667
children?: PlanItemInterface[];
6768
}
@@ -85,3 +86,39 @@ export interface PlanInterface {
8586
contentType?: string;
8687
contentId?: string;
8788
}
89+
90+
export interface ProgramInterface {
91+
id?: string;
92+
name?: string;
93+
slug?: string;
94+
description?: string;
95+
image?: string;
96+
live?: boolean;
97+
churchId?: string;
98+
}
99+
100+
export interface StudyInterface {
101+
id?: string;
102+
name?: string;
103+
slug?: string;
104+
description?: string;
105+
image?: string;
106+
programId?: string;
107+
sort?: number;
108+
}
109+
110+
export interface LessonInterface {
111+
id?: string;
112+
name?: string;
113+
slug?: string;
114+
description?: string;
115+
studyId?: string;
116+
sort?: number;
117+
}
118+
119+
export interface VenueInterface {
120+
id?: string;
121+
name?: string;
122+
lessonId?: string;
123+
sort?: number;
124+
}
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
import React, { useState, useCallback, useEffect } from "react";
2+
import {
3+
Button,
4+
Dialog,
5+
DialogTitle,
6+
DialogContent,
7+
DialogActions,
8+
FormControl,
9+
InputLabel,
10+
Select,
11+
MenuItem,
12+
Stack,
13+
} from "@mui/material";
14+
import { ApiHelper } from "@churchapps/apphelper";
15+
16+
interface Props {
17+
open: boolean;
18+
onClose: () => void;
19+
onSelect: (venueId: string) => void;
20+
}
21+
22+
export const LessonSelector: React.FC<Props> = ({ open, onClose, onSelect }) => {
23+
const [lessonTree, setLessonTree] = useState<any>({});
24+
const [selectedProgram, setSelectedProgram] = useState<string>("");
25+
const [selectedStudy, setSelectedStudy] = useState<string>("");
26+
const [selectedLesson, setSelectedLesson] = useState<string>("");
27+
const [selectedVenue, setSelectedVenue] = useState<string>("");
28+
29+
const loadLessonTree = useCallback(async () => {
30+
try {
31+
const data = await ApiHelper.getAnonymous("/lessons/public/tree", "LessonsApi");
32+
setLessonTree(data || {});
33+
34+
// Auto-select defaults
35+
if (data?.programs?.length > 0) {
36+
const firstProgram = data.programs[0];
37+
setSelectedProgram(firstProgram.id);
38+
39+
if (firstProgram.studies?.length > 0) {
40+
const firstStudy = firstProgram.studies[0];
41+
setSelectedStudy(firstStudy.id);
42+
43+
if (firstStudy.lessons?.length > 0) {
44+
const firstLesson = firstStudy.lessons[0];
45+
setSelectedLesson(firstLesson.id);
46+
47+
if (firstLesson.venues?.length > 0) {
48+
setSelectedVenue(firstLesson.venues[0].id);
49+
}
50+
}
51+
}
52+
}
53+
} catch (error) {
54+
console.error("Error loading lesson tree:", error);
55+
setLessonTree({});
56+
}
57+
}, []);
58+
59+
const getCurrentProgram = useCallback(() => {
60+
return lessonTree?.programs?.find((p: any) => p.id === selectedProgram);
61+
}, [lessonTree, selectedProgram]);
62+
63+
const getCurrentStudy = useCallback(() => {
64+
const program = getCurrentProgram();
65+
return program?.studies?.find((s: any) => s.id === selectedStudy);
66+
}, [getCurrentProgram, selectedStudy]);
67+
68+
const getCurrentLesson = useCallback(() => {
69+
const study = getCurrentStudy();
70+
return study?.lessons?.find((l: any) => l.id === selectedLesson);
71+
}, [getCurrentStudy, selectedLesson]);
72+
73+
const handleProgramChange = useCallback((programId: string) => {
74+
setSelectedProgram(programId);
75+
setSelectedStudy("");
76+
setSelectedLesson("");
77+
setSelectedVenue("");
78+
}, []);
79+
80+
const handleStudyChange = useCallback((studyId: string) => {
81+
setSelectedStudy(studyId);
82+
setSelectedLesson("");
83+
setSelectedVenue("");
84+
}, []);
85+
86+
const handleLessonChange = useCallback((lessonId: string) => {
87+
setSelectedLesson(lessonId);
88+
setSelectedVenue("");
89+
}, []);
90+
91+
const handleVenueChange = useCallback((venueId: string) => {
92+
setSelectedVenue(venueId);
93+
}, []);
94+
95+
const handleSelect = useCallback(() => {
96+
if (selectedVenue) {
97+
onSelect(selectedVenue);
98+
onClose();
99+
}
100+
}, [selectedVenue, onSelect, onClose]);
101+
102+
const handleClose = useCallback(() => {
103+
setSelectedProgram("");
104+
setSelectedStudy("");
105+
setSelectedLesson("");
106+
setSelectedVenue("");
107+
onClose();
108+
}, [onClose]);
109+
110+
useEffect(() => {
111+
if (open) loadLessonTree();
112+
}, [open, loadLessonTree]);
113+
114+
const currentProgram = getCurrentProgram();
115+
const currentStudy = getCurrentStudy();
116+
const currentLesson = getCurrentLesson();
117+
118+
return (
119+
<Dialog open={open} onClose={handleClose} maxWidth="sm" fullWidth>
120+
<DialogTitle>Associate Lesson</DialogTitle>
121+
<DialogContent>
122+
<Stack spacing={3} sx={{ mt: 1 }}>
123+
<FormControl fullWidth>
124+
<InputLabel>Program</InputLabel>
125+
<Select
126+
value={selectedProgram}
127+
onChange={(e) => handleProgramChange(e.target.value)}
128+
label="Program"
129+
>
130+
{lessonTree?.programs?.map((program: any) => (
131+
<MenuItem key={program.id} value={program.id}>
132+
{program.name}
133+
</MenuItem>
134+
))}
135+
</Select>
136+
</FormControl>
137+
138+
<FormControl fullWidth disabled={!selectedProgram}>
139+
<InputLabel>Study</InputLabel>
140+
<Select
141+
value={selectedStudy}
142+
onChange={(e) => handleStudyChange(e.target.value)}
143+
label="Study"
144+
>
145+
{currentProgram?.studies?.map((study: any) => (
146+
<MenuItem key={study.id} value={study.id}>
147+
{study.name}
148+
</MenuItem>
149+
))}
150+
</Select>
151+
</FormControl>
152+
153+
<FormControl fullWidth disabled={!selectedStudy}>
154+
<InputLabel>Lesson</InputLabel>
155+
<Select
156+
value={selectedLesson}
157+
onChange={(e) => handleLessonChange(e.target.value)}
158+
label="Lesson"
159+
>
160+
{currentStudy?.lessons?.map((lesson: any) => (
161+
<MenuItem key={lesson.id} value={lesson.id}>
162+
{lesson.name}
163+
</MenuItem>
164+
))}
165+
</Select>
166+
</FormControl>
167+
168+
<FormControl fullWidth disabled={!selectedLesson}>
169+
<InputLabel>Venue</InputLabel>
170+
<Select
171+
value={selectedVenue}
172+
onChange={(e) => handleVenueChange(e.target.value)}
173+
label="Venue"
174+
>
175+
{currentLesson?.venues?.map((venue: any) => (
176+
<MenuItem key={venue.id} value={venue.id}>
177+
{venue.name}
178+
</MenuItem>
179+
))}
180+
</Select>
181+
</FormControl>
182+
183+
184+
</Stack>
185+
</DialogContent>
186+
<DialogActions>
187+
<Button onClick={handleClose}>Cancel</Button>
188+
<Button onClick={handleSelect} disabled={!selectedVenue} variant="contained">
189+
Associate Lesson
190+
</Button>
191+
</DialogActions>
192+
</Dialog>
193+
);
194+
};

0 commit comments

Comments
 (0)