1+ global q , model , Data
2+
3+ def get_reservations_for_room (reservableIds , startDate , days ):
4+
5+ if not isinstance (reservableIds , list ):
6+ reservableIds = [reservableIds ]
7+
8+ query = '''
9+ SELECT
10+ rb.ReservableId,
11+ rv.MeetingStart,
12+ COALESCE(rv.MeetingEnd, rv.MeetingStart) as MeetingEnd,
13+ COALESCE(NULLIF(rv.SetupMinutes, ''), 0) as SetupMinutes,
14+ COALESCE(NULLIF(rv.SetupMinutes, ''), 0) as TeardownMinutes,
15+ COALESCE(NULLIF(m.Description, ''), o.OrganizationName) as Name,
16+ 0 as Quantity,
17+ m.MeetingId,
18+ o.LeaderName
19+ INTO #reservables
20+ FROM Reservations rv
21+ JOIN Reservable rb ON rv.ReservableId = rb.ReservableId
22+ JOIN Meetings m ON rv.MeetingId = m.MeetingId
23+ JOIN Organizations o ON m.OrganizationId = o.OrganizationId
24+ WHERE rv.MeetingId IS NOT NULL
25+ AND rv.MeetingEnd > '{0}'
26+ AND rv.MeetingStart < DATEADD(day, 1, '{0}');
27+ ''' .format (reservableIds )
28+
29+
30+ def get_reservables (typ ):
31+ return q .QuerySql ("""
32+ SELECT ReservableId,
33+ ParentId,
34+ COALESCE(BadgeColor, '#153aa8') as Color,
35+ Name,
36+ Description,
37+ IsReservable,
38+ IsEnabled,
39+ IsCountable,
40+ Quantity
41+ FROM Reservable
42+ WHERE 1=1
43+ AND ReservableTypeId = {}
44+ AND IsDeleted = 0
45+ AND IsEnabled = 1
46+
47+ ORDER BY ReservableTypeId, Name
48+ ;
49+ """ .format (typ ))
50+
51+ if model .HttpMethod == "post" and Data .v == "saveSigns" :
52+ # save signage configuration
53+ import json
54+
55+ rawData = Data .data
56+ try :
57+ signageData = json .loads (rawData )
58+ model .WriteContentText ("CalendarSignageConfiguration.json" , json .dumps (signageData ), "CalendarSignage" )
59+ print (json .dumps ({"status" : "success" }))
60+ except Exception as e :
61+ model .Log ("Error parsing signage data: {}" .format (str (e )))
62+ print (json .dumps ({"error" : "data parsing error" }))
63+
64+
65+
66+ elif Data .v == "" :
67+ # configuration mode
68+
69+ # import knockout from cdn
70+ # language=html
71+ model .Title = "Calendar Signage Configuration"
72+
73+ # noinspection PyBroadException
74+ try :
75+ originalConfig = model .Content ("CalendarSignageConfiguration.json" )
76+ except :
77+ print ("<p>Caution: could not load existing configuration, starting fresh.</p>" )
78+ originalConfig = None
79+
80+ if originalConfig is None or originalConfig .strip () == "" :
81+ originalConfig = "[]"
82+
83+ ko_form = """
84+ <script>
85+ const originalData = {};
86+ </script>
87+ """ .format (originalConfig )
88+
89+ # Form that lists signs in the system
90+ # language=html
91+ ko_form = ko_form + """
92+ <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.0/knockout-min.js"></script>
93+
94+ <table style="border-collapse: collapse; width: 100%;" data-bind="visible: signs().length > 0">
95+ <thead>
96+ <tr>
97+ <th>Name</th>
98+ <th>Sign Template</th>
99+ <th>Print Copies</th>
100+ <th>Items</th>
101+ <th>Options</th>
102+ </tr>
103+ </thead>
104+ <tbody data-bind="foreach: signs">
105+ <tr>
106+ <td><input data-bind="value: name"/></td>
107+ <td><select
108+ data-bind="options: $parent.types, optionsText: 'name', optionsValue: 'fileName', value: type">
109+ </td>
110+ <td><input type="number" data-bind="value: copies" min="0"/></td>
111+ <td><a data-bind="text: items().length, click: $parent.editSign"></a></td>
112+ <td>
113+ <a data-bind="attr: { href: previewLink }">Preview</a>
114+ <a data-bind="click: $parent.removeSign">Remove</a>
115+ </td>
116+ </tr>
117+ </tbody>
118+ </table>
119+ <button data-bind="click: addSign">Add Sign</button>
120+
121+
122+ <div class="modal" id="edit-sign-dialog" data-keyboard="false" data-backdrop="static" style="background: #0009;">
123+ <div class="modal-dialog modal-md" data-bind="if: currentlyEditingSign() !== null">
124+ <div class="modal-content">
125+ <div class="modal-header">
126+ <button type="button" class="close" data-dismiss="modal" data-bind="click: closeModal" aria-label="Close"><span aria-hidden="true">×</span></button>
127+ <h4 class="modal-title" data-bind="text: 'Editing ' + currentlyEditingSign().name()"></h4>
128+ </div>
129+ <div class="modal-body">
130+ <div class="form-group">
131+ <label for="OrganizationName" class="control-label">Name</label>
132+ <input class="form-control" id="org_OrganizationName" name="org.OrganizationName" type="text" value="">
133+ </div>
134+ <div class="form-group">
135+ <label for="InvolvementType" class="control-label">Involvement Type</label>
136+ <select class="form-control" data-val="true" data-val-number="The field Organization Type must be a number." id="org_OrganizationTypeId" name="org.OrganizationTypeId"><option value="0">(not specified)</option>
137+ <option value="2">Children/Youth Program</option>
138+ <option value="10">Small Group</option>
139+ <option value="20">Adult Class</option>
140+ <option value="40">Missions Trip</option>
141+ <option value="49">Job Application</option>
142+ <option selected="selected" value="50">Administration</option>
143+ <option value="51">Parish Council</option>
144+ <option value="70">Social Event</option>
145+ <option value="75">Conference</option>
146+ <option value="81">Worship Services</option>
147+ <option value="91">Communications</option>
148+ <option value="92">Mobile App</option>
149+ </select>
150+ </div>
151+ </div>
152+ </div>
153+ </div>
154+ </div>
155+
156+
157+
158+
159+ <script>
160+ function Sign(data) {
161+ const that = this;
162+ this.name = ko.observable(data.name);
163+ this.items = ko.observableArray(data.items || []);
164+ this.copies = ko.observable(data.copies || 1);
165+ this.type = ko.observable(data.type || "CalendarSignageDirectional");
166+ this.id = ko.observable(data.id || btoa(Math.random().toString()).substring(0, 6));
167+ this.previewLink = ko.computed(function () {
168+ return "?v=" + that.id();
169+ });
170+
171+ this.copies.subscribe(() => window.signageViewModel.saveSigns());
172+ this.name.subscribe(() => window.signageViewModel.saveSigns());
173+ this.type.subscribe(() => window.signageViewModel.saveSigns());
174+ this.items.subscribe(() => window.signageViewModel.saveSigns());
175+
176+ this.toJson = function () {
177+ return {
178+ name: that.name(),
179+ items: that.items(),
180+ copies: that.copies(),
181+ type: that.type(),
182+ id: that.id()
183+ };
184+ };
185+ }
186+
187+ function ViewModel(data) {
188+ const self = this;
189+ self.signs = ko.observableArray([]);
190+
191+ data.forEach(function (signData) {
192+ self.signs.push(new Sign(signData));
193+ });
194+
195+ self.types = ko.observableArray([
196+ {name: "Directional", fileName: "CalendarSignageDirectional"},
197+ {name: "Reservations", fileName: "CalendarSignageReservations"},
198+ {name: "Event Details", fileName: "CalendarSignageEventDetails"}
199+ ]);
200+
201+ self.currentlyEditingSign = ko.observable(null);
202+
203+ self.currentlyEditingSign.subscribe(() => {
204+ console.log("here");
205+ console.log(self.currentlyEditingSign())
206+ if (self.currentlyEditingSign() !== null) {
207+ $('#edit-sign-dialog').fadeIn();
208+ } else {
209+ $('#edit-sign-dialog').fadeOut();
210+ }
211+ });
212+
213+ self.closeModal = function () {
214+ self.currentlyEditingSign(null);
215+ }
216+
217+ self.addSign = function () {
218+ const newSign = new Sign({name: "New Sign"});
219+ self.signs.push(newSign);
220+ return newSign;
221+ };
222+
223+ self.editSign = function (sign) {
224+ self.currentlyEditingSign(sign);
225+ };
226+
227+ self.removeSign = function (sign) {
228+ self.signs.remove(sign);
229+ };
230+
231+ self.toJson = function () {
232+ return ko.toJS(self.signs().map(s => s.toJson()));
233+ };
234+
235+ self.saveSigns = function () {
236+ // Save signs to server
237+ const formData = new URLSearchParams();
238+ formData.append('data', JSON.stringify(self.toJson()));
239+
240+ // post to ?v=saveSigns
241+ fetch("/PyScriptForm/CalendarSignage?v=saveSigns", {
242+ method: "POST",
243+ credentials: 'include',
244+ body: formData
245+ }).then(response => {
246+ if (!response.ok) {
247+ throw new Error("Network response was not ok");
248+ }
249+ return response.json();
250+ }).then(() => {
251+ console.log("Signs saved successfully!");
252+ })
253+ };
254+
255+ self.signs.subscribe(function (newSigns) {
256+ // Save signs to server on change
257+ self.saveSigns()
258+ });
259+ }
260+
261+ window.signageViewModel = new ViewModel(originalData);
262+ ko.applyBindings(window.signageViewModel);
263+ </script>
264+ """
265+
266+ print (ko_form )
267+
268+
269+ # print("<p>Select Items to print signage for</p>")
270+ # print("<table>")
271+ # for i in [(1, "Rooms"), (2, "Jawns"), (3, "Other Jawns")]:
272+ # print("<tr><td colspan=\"2\"><h2>{}</h2></td></tr>".format(i[1]))
273+ # l = get_reservables(i[0])
274+ # if l:
275+ # for r in l:
276+ # print("""
277+ # <tr>
278+ # <td><input type="checkbox" id="{1}" /></td>
279+ # <td><label for="{1}">{0}</label></td>
280+ # """.format(r.Name, r.ReservableId))
281+ #
282+ # if i[0] == 1:
283+ # print("""
284+ # <td><input type="checkbox" id="children-{1}" /></td>
285+ # """.format(r.Name, r.ReservableId))
286+ #
287+ # else:
288+ # print("<td></td>")
289+ #
290+ # print("</tr>")
291+ # print("</table>")
292+ #
0 commit comments