359 Commits

Author SHA1 Message Date
Scott Idem
792c496d46 Setting a new version for this app 2024-09-12 13:16:40 -04:00
Scott Idem
faf37f8159 New branch and updates to the workspace file 2024-09-12 13:09:12 -04:00
Scott Idem
5b8121bfc7 Starting new branch and updating packages 2024-09-12 13:03:51 -04:00
Scott Idem
32f24f8ffa Minor update to style 2024-09-09 00:07:25 -04:00
Scott Idem
eacd40ac21 Clean up of the launcher links still... 2024-09-09 00:04:59 -04:00
Scott Idem
bf5bdd4a3e Work on the links to the legacy and new launchers. 2024-09-08 23:28:34 -04:00
Scott Idem
5fcae3b047 Sort of fix for the agreement text (LCI buttons) not showing correctly. 2024-09-06 18:50:44 -04:00
Scott Idem
8b913b73f8 Working on adjusting the permissions for session POC. They can upload/download files for the session and each presenter. 2024-09-04 16:06:50 -04:00
Scott Idem
86dc7797e0 Minor changes related to the site passcodes. 2024-09-04 15:19:45 -04:00
Scott Idem
d5d28149ad More work on making things look better. File counts look nicer. 2024-09-04 14:41:02 -04:00
Scott Idem
917cca09ce Cleaning up the hide/unhide buttons 2024-09-04 13:31:47 -04:00
Scott Idem
3919347383 General clean up and standardizing of things. More option buttons. Show/hide from launcher. 2024-09-04 13:05:21 -04:00
Scott Idem
5aaaaa164d Now with search by location name! 2024-09-03 17:42:15 -04:00
Scott Idem
e6694718e7 Work on location links and fixing presenters not showing correctly on session view page. 2024-09-03 16:41:54 -04:00
Scott Idem
9a0112e884 Work on location views and editing. Also session list clean up. 2024-09-03 14:51:36 -04:00
Scott Idem
acf89f3fa5 Style clean up 2024-08-23 18:35:27 -04:00
Scott Idem
4881fcf7f2 Hide the event files button for now. 2024-08-23 16:39:23 -04:00
Scott Idem
4fa8d0368f Working on the styling some more. 2024-08-23 16:34:28 -04:00
Scott Idem
014d244019 Merge remote-tracking branch 'refs/remotes/origin/ae_app_template_dev' into ae_app_template_dev 2024-08-23 14:35:17 -04:00
Scott Idem
4dbdd16bd0 Recovering from something that broke the styling. It is not 100% right, but much better. 2024-08-23 14:26:17 -04:00
Scott Idem
45d7cba562 General clean up. Trying to make things load faster and more smoothly. 2024-08-21 18:55:12 -04:00
Scott Idem
fed37a77b8 Working on sign in checking and permissions. This probably still needs to be reviewed some more. 2024-08-21 15:34:34 -04:00
Scott Idem
d8edd658b0 Adding a new notes module I guess. Because why not. 2024-08-20 21:00:03 -04:00
Scott Idem
5139a706d0 Removing hardcoded LCI related. General clean up of things. 2024-08-20 12:59:35 -04:00
Scott Idem
608bef7f21 Wrapping up for the day 2024-08-19 18:06:36 -04:00
Scott Idem
c61d3a4dca Trying to make this LiveQuery work. 2024-08-19 17:56:32 -04:00
Scott Idem
4871464adf Minor clean up 2024-08-19 16:45:11 -04:00
Scott Idem
722acdaa59 Apparently not much with badge printing... Cleaned up some code. 2024-08-19 16:30:27 -04:00
Scott Idem
1d496eb769 Duplicated and modified how the event file manager works slightly. 2024-08-19 15:23:34 -04:00
Scott Idem
75b0e53114 General clean up and renaming of functions. 2024-08-19 14:53:28 -04:00
Scott Idem
6aa499c79b Package updates 2024-08-19 14:34:40 -04:00
Scott Idem
fefd7c8027 Dim hidden sessions and presenters in the list 2024-08-19 14:24:10 -04:00
Scott Idem
85138e7b44 Wrapping up for the day. It is Friday. Things mostly work. 2024-08-16 18:34:54 -04:00
Scott Idem
68727d24cf Hide the Copy Access Link button if no person ID linked 2024-08-16 18:02:34 -04:00
Scott Idem
fa55e96be2 Refresh files after upload. For now this clears everything. It is may not be the most efficient, but it works. 2024-08-16 17:41:34 -04:00
Scott Idem
b0e15700b5 Adding config options and toggles for various things. 2024-08-16 17:18:15 -04:00
Scott Idem
37801ca769 Fixes for the reports. General clean up all around. Better usage of log_lvl. 2024-08-16 13:14:18 -04:00
Scott Idem
ca563fdf1f Merge remote-tracking branch 'refs/remotes/origin/ae_app_template_dev' into ae_app_template_dev
Merging changes from yesterday. Thought I did this already.
2024-08-16 10:06:47 -04:00
Scott Idem
fed5d2de65 Clean up based on notes. Adding some JSON event config options for presenter agree and presenter bio. 2024-08-16 10:06:16 -04:00
Scott Idem
f58cd9611b Config change 2024-08-15 21:29:37 -04:00
Scott Idem
7d167444c4 Cleaned up the presenter view. Less fields show if the person is not linked. 2024-08-15 20:18:09 -04:00
Scott Idem
5208480614 Made the session menu look nicer. 2024-08-15 19:52:12 -04:00
Scott Idem
f674503b21 Fixes for the QR codes refreshing too easily. Added option to turn the QR codes off and on. Need to add an event level setting or something. 2024-08-15 18:51:16 -04:00
Scott Idem
002c283c68 Working on dealing with the QR codes re-generating too easily. 2024-08-15 18:04:14 -04:00
Scott Idem
46cc89ad92 Bug fixes for the bio field and copy button 2024-08-15 16:34:34 -04:00
Scott Idem
f209f3ce37 Bug fix for biography copy button 2024-08-15 16:14:01 -04:00
Scott Idem
ef62b30dc9 Now with copy button for presenter bio 2024-08-15 15:49:26 -04:00
Scott Idem
fdca94b625 Minor updates to access 2024-08-15 15:42:18 -04:00
Scott Idem
f526e9094c Various bug fixes. Improvements to the security. Now with super and manager and others. 2024-08-15 15:35:00 -04:00
Scott Idem
35052898b4 Clean up. New ability to save the session search text. 2024-08-15 14:14:41 -04:00
Scott Idem
146bea0a67 Staring work on getting Electron working from Svelte app. Wrapping up for the day. 2024-08-14 19:23:29 -04:00
Scott Idem
cc4588c8a6 Renaming more of the standard object functions. 2024-08-14 16:16:56 -04:00
Scott Idem
0ec9cbbd08 Renaming standard object functions 2024-08-14 16:06:21 -04:00
Scott Idem
be81122e4e General clean up 2024-08-14 15:57:57 -04:00
Scott Idem
56c16bef10 Minor changes 2024-08-14 14:37:53 -04:00
Scott Idem
380a8d2ad3 Allow trusted access to new report 2024-08-14 14:07:21 -04:00
Scott Idem
0d48362529 Work on CRUD v2 API calls. Added sessions without files report. 2024-08-14 14:05:48 -04:00
Scott Idem
efedc88ade Minor fix for help buttons and button styling 2024-08-14 09:39:35 -04:00
Scott Idem
ca2dc11206 Done for the night. 2024-08-13 21:40:14 -04:00
Scott Idem
bdfb276199 Now with better reports showing and status. 2024-08-13 21:36:01 -04:00
Scott Idem
06a1d7a771 Cleaning things up. Minor bug fixes. 2024-08-13 20:57:19 -04:00
Scott Idem
53fea0d25d Cleaned up the menus. Added new options for max qry limits. 2024-08-13 20:01:44 -04:00
Scott Idem
37b2145f81 Now with ability to toggle hidden and disabled sessions. 2024-08-13 18:58:56 -04:00
Scott Idem
e83623526c Minor clean up 2024-08-13 16:52:38 -04:00
Scott Idem
3639342356 Minor bug fix and clean up 2024-08-13 16:48:35 -04:00
Scott Idem
00fcd8e747 Added ability to upload files individually to get the % uploaded. Added show/hide of manage files for sessions and presenters. Other clean up. 2024-08-13 16:42:10 -04:00
Scott Idem
d5dbeeabf7 Maybe wrapping up for the day. 2024-08-12 18:41:33 -04:00
Scott Idem
df36727540 Working on a better file upload element and component. Slow progress... 2024-08-12 18:35:36 -04:00
Scott Idem
074cf154f2 Improvement with file counts and related 2024-08-09 19:33:47 -04:00
Scott Idem
d7dfef4fe0 Wrapping up for the day/week. It is my birthday weekend! 2024-08-09 19:01:45 -04:00
Scott Idem
9a1995dd9f Lots of changes. Things are working better. Files are now showing for the session and presenter. Next is location and event. 2024-08-09 17:50:54 -04:00
Scott Idem
30e6384772 I quite for the night! The presentation list shows now... 2024-08-08 20:42:04 -04:00
Scott Idem
14fc1ee146 Now I am trying to get the presentation list to display... Why won't this work...? Adding URL params seems to have helped some. 2024-08-08 19:51:03 -04:00
Scott Idem
4ddc775aaa Things are finally working better again with the liveQuery. I hope. 2024-08-08 16:55:50 -04:00
Scott Idem
4141524d83 Just saving things... Not making good progress today. 2024-08-08 15:48:49 -04:00
Scott Idem
f407565fc7 Fixed up the new Launcher. The Dexie liveQuery is now working better. Added await tick();. 2024-08-07 18:37:45 -04:00
Scott Idem
cb1f4343db Show star for priority presenter 2024-08-07 17:32:05 -04:00
Scott Idem
ccd91571ce Bug fixes for sign in and related 2024-08-07 17:21:10 -04:00
Scott Idem
75ee8e1b5c Working on bug fix for sign in vs the selected presentation and presenter. Partially fixed. 2024-08-07 16:09:17 -04:00
Scott Idem
7aebf24996 Should have saved my work earlier... General clean up of initial API calls and saving to IDB. Other fixes and updates. 2024-08-07 15:26:58 -04:00
Scott Idem
0d34f81fa7 Wrapping up for the day. The new launcher is partially working. There is a lot of work to do. 2024-08-02 19:11:35 -04:00
Scott Idem
352639e702 Pulled out the event reports page menu. And other clean up. 2024-08-02 12:05:00 -04:00
Scott Idem
8d7627fd36 Clean up of button text 2024-08-01 21:08:45 -04:00
Scott Idem
40293e25b4 Making things scale better 2024-08-01 20:42:28 -04:00
Scott Idem
bf31a3f596 Minor menu show/hide fix 2024-08-01 20:01:34 -04:00
Scott Idem
ff498ed49e Fixed spacing... 2024-08-01 19:55:26 -04:00
Scott Idem
2177f6c379 Now with the event session search menu separated out. Also other clean up. 2024-08-01 19:52:52 -04:00
Scott Idem
98d09bac76 The session and presenter headers both look good. 2024-08-01 18:56:28 -04:00
Scott Idem
e0e380e450 Bug fixes and small improvements. The session page menu is now separate. Still testing that out. 2024-08-01 17:21:59 -04:00
Scott Idem
e7b7948b06 Going live with the new menu after some testing. 2024-08-01 16:33:03 -04:00
Scott Idem
cf9f914412 The new menu for the session page is working well. Time for clean up. 2024-08-01 15:43:39 -04:00
Scott Idem
2fca5b2c3b Creating new session_view.svelte. General clean up related to that and presenter_view.svelte 2024-08-01 10:46:09 -04:00
Scott Idem
f8b53baee8 Making things look nicer. 2024-07-25 18:26:38 -04:00
Scott Idem
86c8aa6c83 Now with hide files from launcher working. event_file.hide 2024-07-25 18:20:17 -04:00
Scott Idem
4a70869896 Improving person reports and related 2024-07-25 13:25:25 -04:00
Scott Idem
0ca8da1a6e Bug fix for total file count for a session 2024-07-25 12:51:34 -04:00
Scott Idem
d756059ad4 Now with ability to clear IDB event_file list 2024-07-25 12:36:39 -04:00
Scott Idem
6b9284951e General improvements to reports 2024-07-25 11:29:59 -04:00
Scott Idem
8b53cd2b7f End user should not see the person link 2024-07-24 18:33:21 -04:00
Scott Idem
fdb435cd1e Got rid of dollar symbol 2024-07-24 18:27:45 -04:00
Scott Idem
37c51cee29 Now with JSON validity checking. Done for the day. 2024-07-24 18:22:19 -04:00
Scott Idem
274b599ff1 Now with new button toggles and edit for JSON data! 2024-07-24 18:06:10 -04:00
Scott Idem
98849427d9 Scroll bars only show when needed in Chrome now. "auto" instead of "scroll" 2024-07-24 15:05:25 -04:00
Scott Idem
027d7a781d General clean up related to permissions and updating fields. 2024-07-24 15:00:48 -04:00
Scott Idem
c41be23995 Package updates and related 2024-07-23 18:40:15 -04:00
Scott Idem
b0633a5c24 Bug fixes for the file rename. 2024-07-19 17:01:42 -04:00
Scott Idem
b2293784e0 Now with the ability to rename files. Had to add a new Dexie update IDB function. 2024-07-19 16:40:56 -04:00
Scott Idem
af17a05022 Now with QR codes for sessions and presenters! 2024-07-18 17:15:12 -04:00
Scott Idem
a6f8f00e9e Implementing bug fix for Svelte params not being ready under my data value. Loading and referencing the params directly/explicitly instead. 2024-07-18 10:09:56 -04:00
Scott Idem
070e714aff Bug fix for loading pages with params! I think this has been a root cause of some of the issues for a while now. 2024-07-18 09:21:29 -04:00
Scott Idem
43488b8f76 Wrapping up for the day. I need to research this. Why does the first link (anchor tag) that is hovered over (triggers pre-load) fail if the URL has a “slug” value? Or any URL??? Any links after the first seem to pre-load fine. 2024-07-17 18:30:08 -04:00
Scott Idem
d16c47fedf Testing preloading 2024-07-17 18:24:43 -04:00
Scott Idem
064bba3d62 Reports can set max count. Bug fixes. Clean up. 2024-07-17 17:08:09 -04:00
Scott Idem
625169a321 Work on new core person list, view, and edit 2024-07-17 14:59:15 -04:00
Scott Idem
ad1e42010a Show more results by default 2024-07-12 16:24:47 -04:00
Scott Idem
997f470ebe Now with a new recent files report. 2024-07-12 16:20:23 -04:00
Scott Idem
47c742d004 Wrapping up for the day. The first report looks pretty good. 2024-07-11 17:44:43 -04:00
Scott Idem
945c943c61 Added a reports section and the first report. Agreed presenters. 2024-07-11 17:01:44 -04:00
Scott Idem
7eb3080f46 Updating packages. Stuck with issues related to ESLint and TypeScript. A version conflict. 2024-07-11 13:52:48 -04:00
Scott Idem
1bf90f128f Updates for the browser title. Wrapping up for the day! July 4th week! 2024-07-03 18:48:28 -04:00
Scott Idem
8f2eb2c27e Forgot to lock some fields down. And other minor changes. 2024-07-03 18:23:59 -04:00
Scott Idem
4aae2bead4 Separating out components and functions to make things more modular. 2024-07-03 17:48:06 -04:00
Scott Idem
270a1429f8 None code change 2024-07-03 11:54:31 -04:00
Scott Idem
a2d3d5b1f7 NPM package updates 2024-07-03 11:45:30 -04:00
Scott Idem
26a0a1dbd6 Working on new inline components for presenter list and event file list. 2024-07-02 18:53:41 -04:00
Scott Idem
889500e80d Finally got the horizontal scroll working correctly with the table. 2024-07-02 18:17:38 -04:00
Scott Idem
d8e062b8c7 Work in progress of moving the session list out to a separate component. 2024-07-02 15:42:45 -04:00
Scott Idem
a1515ba6b6 Code clean up 2024-07-02 14:35:12 -04:00
Scott Idem
27bed2f532 At good point for session searching. 2024-07-02 14:19:04 -04:00
Scott Idem
f4006e7226 The rate limited and delayed search is now working. 2024-07-02 14:00:39 -04:00
Scott Idem
afbe396caf Cleaning up search 2024-07-02 11:54:07 -04:00
Scott Idem
aae19249d4 More efficient query results processing 2024-07-02 11:38:33 -04:00
Scott Idem
d410953ce4 Work on new LiveQuery search results 2024-07-02 09:42:52 -04:00
Scott Idem
40aba339f8 Work on LiveQuery 2024-07-02 09:33:16 -04:00
Scott Idem
ed89c61aed Slight change to header padding 2024-07-01 23:30:43 -04:00
Scott Idem
6d06347e0a Will come back to the LiveQuery undefined thing later... 2024-07-01 20:37:19 -04:00
Scott Idem
acc39ecb50 Wrapping up for the day. Trying to get LQ to work with searching and bulkGet. 2024-07-01 20:33:57 -04:00
Scott Idem
861107c2fd Ready to move on to other areas. 2024-07-01 17:01:48 -04:00
Scott Idem
245757b501 Working on the logic for permissions 2024-07-01 16:53:54 -04:00
Scott Idem
88b0042919 This should have been saved earlier. Lots of moving code around to and clean up. 2024-07-01 16:22:10 -04:00
Scott Idem
9de9d31101 Trying to fix scrolling of the table. 2024-06-28 23:24:29 -04:00
Scott Idem
acaff7634d A lot of code clean up. Also making things look better. 2024-06-28 17:56:39 -04:00
Scott Idem
9f7a19c4b9 Making things look nicer 2024-06-28 13:06:13 -04:00
Scott Idem
e6aec67247 Minor changes 2024-06-28 12:17:43 -04:00
Scott Idem
4183c9022c Now with presenter biography. Used the speakers collection that was done for CHOW as the basis. 2024-06-28 12:02:45 -04:00
Scott Idem
298f87960a Now with ability to sync person record to presenter record. Also some other editing. 2024-06-28 10:45:37 -04:00
Scott Idem
a0085723c9 Now with new file manager 2024-06-28 09:48:12 -04:00
Scott Idem
d01ab2479f Ready to swap out the temporary presenter view file manager section 2024-06-28 09:42:51 -04:00
Scott Idem
2d490d8058 Fixed presentation name edit permissions 2024-06-27 18:43:01 -04:00
Scott Idem
a34d2af18e Show full SHA hash in title 2024-06-27 18:24:25 -04:00
Scott Idem
12c778c7e2 Now with a better file manager. It still needs work. 2024-06-27 18:19:29 -04:00
Scott Idem
37ac30c56c Working on new standalone event file manage element 2024-06-27 15:51:49 -04:00
Scott Idem
8c8748b571 Making more fields us the LiveQuery. Migrated format bytes function. General clean up. 2024-06-27 10:57:19 -04:00
Scott Idem
20e1c46461 Making things look better. Now with a person look up for the presenter record. Wrapping up for the day. 2024-06-26 18:19:17 -04:00
Scott Idem
4d7e48a170 Making things look pretty 2024-06-26 14:39:30 -04:00
Scott Idem
dd9c48e801 Minor fixes and new warning for outdated "app" version. 2024-06-26 14:06:38 -04:00
Scott Idem
7faa9d0459 Work on help information for session search and session view 2024-06-26 11:38:20 -04:00
Scott Idem
6a22f84f23 Failed to switch to LiveQuery for presenter list 2024-06-25 19:07:38 -04:00
Scott Idem
b604eaee56 Saving before trying to use live query with presentation list 2024-06-25 18:10:14 -04:00
Scott Idem
68d376b88d Now able to do stuff with the locations 2024-06-25 18:06:56 -04:00
Scott Idem
0090058238 Just working on select option list and related. 2024-06-25 14:50:40 -04:00
Scott Idem
a62ea7dc8d Making things work better. Adding CRUD select option list. 2024-06-25 14:05:03 -04:00
Scott Idem
21ad9d900c Adding the ability to quickly edit most fields. Other general clean up. 2024-06-25 11:37:03 -04:00
Scott Idem
4ad51b8e0b Wrapping up for the day. Now with ability to add a person. 2024-06-24 19:45:15 -04:00
Scott Idem
384f91bbe7 Create presentations and presenters. Making things look nicer. 2024-06-24 19:09:40 -04:00
Scott Idem
58a975bfe9 Updating npm and Svelte 2024-06-24 16:04:44 -04:00
Scott Idem
c6b7c7e803 Better (less) logging and other clean up 2024-06-24 15:51:30 -04:00
Scott Idem
0c4185f74c General code clean up 2024-06-24 14:42:14 -04:00
Scott Idem
31ba1c9200 Split up the giant events functions file! 2024-06-24 14:32:25 -04:00
Scott Idem
5211f83f23 Now with file counts on the search results! Done for the day. 2024-06-21 16:57:43 -04:00
Scott Idem
ecf2b3eca8 Now with updated POC edit and other 2024-06-21 16:03:08 -04:00
Scott Idem
e5cff89acb Now with search on presenter's name and email 2024-06-21 15:08:58 -04:00
Scott Idem
87b4f22bb1 Added select no POC option 2024-06-21 12:29:32 -04:00
Scott Idem
2552e1a839 Now with upload and download percent! Also better editing for session POC. 2024-06-21 12:25:36 -04:00
Scott Idem
fd114bce22 Now with the ability to edit a presentation name. Yay. 2024-06-20 18:32:24 -04:00
Scott Idem
991cb1e9da Working on ability to change the presentation name and session name... Making progress. Need to figure out why the file list does not reload correctly right after saving. 2024-06-20 17:45:00 -04:00
Scott Idem
d49f73583c Now with clear search text button. 2024-06-20 13:47:40 -04:00
Scott Idem
8c52722408 Bug fixes and clean up of Dexie DB related 2024-06-19 16:27:16 -04:00
Scott Idem
06add80718 A lot of cosmetic clean up and some code clean up. Also new util functions from old Svelte NPM library. 2024-06-19 14:01:15 -04:00
Scott Idem
5ef2d05e9c Enable emailing sign in links 2024-06-18 18:49:30 -04:00
Scott Idem
baf354fd46 Minor text change 2024-06-18 15:53:20 -04:00
Scott Idem
8044cd0723 POC sign is mostly working now 2024-06-18 15:52:14 -04:00
Scott Idem
519525540c File uploads for event presenters works. Other minor clean up. 2024-06-14 16:38:15 -04:00
Scott Idem
97f15f41f7 Finally got the presenter file upload working better. 2024-06-14 16:23:10 -04:00
Scott Idem
06df9a6230 Everything is working except for the file uploads 2024-06-14 14:42:49 -04:00
Scott Idem
65daf86cc7 General clean up of things 2024-06-14 11:23:37 -04:00
Scott Idem
37547a96d8 Time for bed! 2024-06-14 00:39:38 -04:00
Scott Idem
0156426f4b Trying to get things ready for tomorrow. Now with saving of opt outs and other. 2024-06-14 00:34:24 -04:00
Scott Idem
58d25e922c Stopping for dinner and a break. 2024-06-13 19:08:09 -04:00
Scott Idem
6bcc554737 Clean up of auth logic 2024-06-13 15:42:30 -04:00
Scott Idem
84f6f1eda8 Trying to wrap up for the day. 2024-06-12 18:58:06 -04:00
Scott Idem
b368abc91a Almost ready for LCI demo... 2024-06-12 13:23:56 -04:00
Scott Idem
987e411956 Now with session searching working 2024-06-12 13:00:27 -04:00
Scott Idem
bbd403b96d More updates 2024-06-11 20:02:37 -04:00
Scott Idem
98cd149d2c Lots of work on things for LCI! Should have saved more often. 2024-06-11 19:31:44 -04:00
Scott Idem
7cd71299b3 Changes for CHOW deadline 2024-06-07 11:47:28 -04:00
Scott Idem
87ef4cc6b9 Better update to the results cap based on admin or trusted 2024-05-29 15:09:31 -04:00
Scott Idem
8b201a68ed Increased list cap 2024-05-29 15:05:33 -04:00
Scott Idem
359c147167 Moving things to SK. Added events and sessions. 2024-05-24 19:02:52 -04:00
Scott Idem
d9ff625db6 More code clean up 2024-05-23 19:45:17 -04:00
Scott Idem
0005ba7dc9 Code clean up 2024-05-23 18:59:50 -04:00
Scott Idem
42fef3feb8 Re-working the API library functions and files 2024-05-23 18:20:31 -04:00
Scott Idem
fa58d1accb Changes from before AAPOR 2024-05-20 17:24:23 -04:00
Scott Idem
f72d7be5b2 Work on general clean up. Better export and email of sponsor data 2024-05-03 17:07:08 -04:00
Scott Idem
a3a32e188d Should have saved earlier... 2024-04-25 16:11:18 -04:00
Scott Idem
94d0cfeb4d Working on better bug fix for downloading export files. Some columns were missing. 2024-04-23 18:52:41 -04:00
Scott Idem
69c1250961 Improved downloading export files. 2024-04-23 17:42:44 -04:00
Scott Idem
2aff1aadbe Export now works for Sponsors, Speakers, and Leads 2024-04-23 17:10:24 -04:00
Scott Idem
ca04e9739f Saving my work! 2024-04-23 16:36:08 -04:00
Scott Idem
38e73cb40c Adding back in the sponsorship export stuff I was working on... Annoyed. 2024-04-23 15:53:43 -04:00
a87b4d53a0 Unknown changes from last week in Prague? 2024-04-23 15:37:51 -04:00
f8e81bf7e4 Better style 2024-04-11 11:32:45 -04:00
d242948d7e Show or hide alert. Enable or disable the default to scan 2024-04-11 11:17:59 -04:00
21ee101007 Clean up of style 2024-04-11 10:40:23 -04:00
2b61b8f4a5 Style updates 2024-04-11 10:11:44 -04:00
ab268532da Padding change and minor layout change 2024-04-11 06:27:46 -04:00
920dd176fe I am done for the night/morning... 2024-04-10 20:31:32 -04:00
5411df5893 Trying things... 2024-04-10 04:45:48 -04:00
ab906e4af1 More comments 2024-04-10 00:16:08 -04:00
46dcd389a4 This is nearly working. 2024-04-10 00:14:53 -04:00
f405d1b3b7 Quick save of things 2024-04-10 00:09:57 -04:00
0aae7f9361 I don't know 2024-04-09 23:35:19 -04:00
a51e96ea6e Hopefully this works... QR stop and start? 2024-04-09 23:05:32 -04:00
f68bccddb9 Trying to make things work for the morning... 2024-04-09 21:25:12 -04:00
4460b38098 Style clean up 2024-04-09 06:34:34 -04:00
8e6ab2c223 More generic short_name for PWA 2024-04-09 04:30:22 -04:00
d64a20e5b3 Done for the night for real! 2024-04-08 20:27:17 -04:00
f5ab1cecc1 Done for the night. 2024-04-08 20:11:47 -04:00
ef583e1328 Getting the badge search really ready 2024-04-08 19:12:44 -04:00
9eee2a928b Now supports the new redirect to the new search 2024-04-08 13:15:39 -04:00
1ae1a3d989 The AND LIKE query is now working! 2024-04-07 17:26:48 -04:00
bde3229270 Working on making the LIKE query work correctly. 2024-04-07 14:06:31 -04:00
02af46a48f The leads should be ready to go now..... 2024-04-07 12:59:06 -04:00
Scott Idem
562479313d Hiding not ready warning messages 2024-04-05 11:39:11 -04:00
Scott Idem
a5b0720933 More fixes 2024-04-04 23:39:18 -04:00
Scott Idem
847fad3151 Last minute updates 2024-04-04 23:31:59 -04:00
Scott Idem
16f65cf85f Now with much better badge search function. And bug fix for Payment tab. 2024-04-04 21:33:45 -04:00
Scott Idem
5671423467 Getting the badges up and running again 2024-04-03 19:37:28 -04:00
Scott Idem
8d2f4e30f4 Almost everything works!! Need to clean up export file. Missing custom questions and similar. 2024-04-03 18:10:47 -04:00
Scott Idem
9c85914b9f Progress 2024-04-03 16:28:11 -04:00
Scott Idem
ae1764579e Making things look good and fewer bugs 2024-04-03 15:54:51 -04:00
Scott Idem
b5588fd9a1 Slow and steady progress getting things working more smoothly. 2024-04-03 14:54:33 -04:00
Scott Idem
1555f0f8d0 Fixes for saving custom leads questions and adding by badge ID 2024-04-03 11:22:38 -04:00
Scott Idem
3abe92a2dc Various bug fixes for CHOW 2024-04-01 20:48:16 -04:00
Scott Idem
78b5fc1068 I am done...? 2024-03-29 20:33:10 -04:00
Scott Idem
841367afeb Changes have been made... 2024-03-29 15:35:40 -04:00
Scott Idem
0e26765312 General clean up. Less debug. Things work better? 2024-03-29 12:15:50 -04:00
Scott Idem
c0e1d666f4 Minor 2024-03-28 19:31:09 -04:00
Scott Idem
7a4a4cab5e Now with auto hide header and footer 2024-03-28 19:16:07 -04:00
Scott Idem
741878172c Less logging 2024-03-28 19:01:26 -04:00
Scott Idem
2b1b2b7d07 Now with ability to email license sign in link 2024-03-28 18:55:31 -04:00
Scott Idem
9851c69c30 Making things work smoothly 2024-03-28 17:34:19 -04:00
Scott Idem
86972f5a02 Svelte framework and lib updates 2024-03-28 13:23:58 -04:00
Scott Idem
b7bf152366 General updates 2024-03-28 12:58:23 -04:00
Scott Idem
7cc23077f3 Done for the night I guess. 2024-03-27 20:15:30 -04:00
Scott Idem
b336f18512 Testing auto reloading data stores. 2024-03-27 19:21:57 -04:00
Scott Idem
378ae11224 I think things are mostly working now... 2024-03-27 19:21:39 -04:00
Scott Idem
8d8fb0b638 I guess this is better than it was... 2024-03-27 17:55:31 -04:00
Scott Idem
3082c07e3e Should have saved my progress earlier. Trying to redo things without using localStorage initially. Shared data... 2024-03-27 11:36:06 -04:00
Scott Idem
a8a2131361 I am not really sure... I just want it to load correctly. 2024-03-26 20:15:24 -04:00
Scott Idem
a30690ea2a Mostly working before major fix for data shared. 2024-03-26 18:25:43 -04:00
Scott Idem
f20c6ef706 Finally getting the initial loading better 2024-03-26 17:12:35 -04:00
Scott Idem
4d486a580c Trying to make things work better... 2024-03-26 14:24:35 -04:00
Scott Idem
040e1e71e3 One last little bug 2024-03-25 20:25:15 -04:00
Scott Idem
54fb837581 Bug fix for QR scan. Clean up for the day! 2024-03-25 20:15:02 -04:00
Scott Idem
3ddef770c0 General work through out the day. Lots of interruptions from the dogs. 2024-03-25 19:26:49 -04:00
Scott Idem
b0f2e2ccdf Done for the day 2024-03-22 19:16:14 -04:00
Scott Idem
f97c83db03 Quick save before trying more drastic options for sorting and filtering... 2024-03-22 14:07:07 -04:00
Scott Idem
742205b84b Done for the night! 2024-03-21 20:02:17 -04:00
Scott Idem
976f4fe8c0 Done for the night 2024-03-21 19:45:42 -04:00
Scott Idem
cd79213b37 Wrapping up for the day? 2024-03-21 18:29:12 -04:00
Scott Idem
18c1c84044 This is a good point for things. Looks good and working well. 2024-03-21 18:13:05 -04:00
Scott Idem
7381797a28 This is just a good clean point of development. Still a lot of work though! 2024-03-21 15:20:48 -04:00
Scott Idem
c490bca265 Stuck and done for the night 2024-03-20 19:39:48 -04:00
Scott Idem
e21b7ef584 General clean up and making things a least look real. 2024-03-20 16:33:36 -04:00
Scott Idem
84e3098b72 Lots of general clean up and fixes. 2024-03-20 13:31:42 -04:00
Scott Idem
fbbaa1392b Wrapping up for the day. Lots of changes. 2024-03-19 20:23:42 -04:00
Scott Idem
19d2dd630b Minor fixes. Passes the client-reference-id to Stripe 2024-03-19 13:10:46 -04:00
Scott Idem
e4687aab2f Finalish updates before sending emails to ISHLT exhibitors 2024-03-19 11:38:47 -04:00
Scott Idem
d3ae087cd6 Lots of updates.... 2024-03-18 21:36:03 -04:00
Scott Idem
9b02b2f86c Bug fix for exhibit_id missing. Why? 2024-03-15 18:46:34 -04:00
Scott Idem
7d86a9b40f Wrapping up for the day? Now with iframe sort of support 2024-03-15 18:02:12 -04:00
Scott Idem
0400aa429b It has been a long two or three weeks... 2024-03-15 17:48:14 -04:00
Scott Idem
68b0efb6c9 Now with QR code scanner! 2024-03-14 20:31:37 -04:00
Scott Idem
20b42ac6aa Things are working! 2024-03-14 19:43:54 -04:00
Scott Idem
a97e5666a7 Just working on things. Slow progress... 2024-03-14 18:11:09 -04:00
Scott Idem
8bf1892bc7 Working on adding/updating licenses 2024-03-13 19:53:10 -04:00
Scott Idem
3f664eb5c0 Saving my work and trying something a little different. Using a number as the id instead of the email address. I feel like this will also cause issues. 2024-03-13 18:06:22 -04:00
Scott Idem
3c30664b2b Last minute work for CHOW. Hopefully done soon... 2024-03-13 10:32:22 -04:00
Scott Idem
fd4f2bdf35 Finally working Events - Leads for exhibitors 2024-03-12 19:28:10 -04:00
Scott Idem
7d1a4b735b Making things look nicer and more complete. 2024-03-12 14:29:16 -04:00
Scott Idem
a5431070d3 Minor changes 2024-03-11 14:06:53 -04:00
Scott Idem
ef2597d114 Bug fixes and clean up for CHOW 2024-03-11 12:48:23 -04:00
Scott Idem
1559bae11c General checks and clean up of things 2024-03-10 16:01:53 -04:00
Scott Idem
b6ba167a86 Done for the night! 2024-03-08 21:17:07 -05:00
Scott Idem
4136c08cdb Sponsor Hub part looks pretty good now. Still need to enable the delete buttons. 2024-03-08 21:09:58 -05:00
Scott Idem
875f327c90 Speakers form is now working pretty well. Including delete. 2024-03-08 18:00:36 -05:00
Scott Idem
b53566aa41 Minor changes 2024-03-08 14:41:36 -05:00
Scott Idem
d9ee195590 Documentation for what reason? 2024-03-08 13:08:54 -05:00
Scott Idem
409872ed4d More changes 2024-03-08 11:43:32 -05:00
Scott Idem
2ada1419d8 Lots of general clean up and work for CHOW going live 2024-03-08 11:27:18 -05:00
Scott Idem
5a147a98bb I am done for the night... 2024-03-08 00:09:17 -05:00
Scott Idem
1694dfb5c5 Getting ready to implement Dexie for Svelte 2024-03-07 13:33:51 -05:00
Scott Idem
ff00ec5c91 Ready to demo for Precon CHOW again 2024-03-07 12:09:23 -05:00
Scott Idem
c6abc0abca Clean up for CHOW... 2024-03-07 11:28:30 -05:00
Scott Idem
b020ded01c Changes. Work on new review page searching. 2024-03-06 20:39:38 -05:00
Scott Idem
aa712284ce Just worki on things 2024-03-06 13:47:41 -05:00
Scott Idem
e71cdab353 Wrapping up for the night. Things are working better. There are still API request misses or something. 2024-03-05 20:35:38 -05:00
Scott Idem
bed4f4a0f2 Work on the new Data Store element 2024-03-05 17:01:37 -05:00
Scott Idem
19a6ff6dbe Work on expanding the routes 2024-03-04 20:55:48 -05:00
Scott Idem
6c60ee3086 More quick updates and clean up 2024-03-04 13:43:24 -05:00
Scott Idem
a0947e349a General clean up for CHOW. 2024-03-04 10:59:15 -05:00
Scott Idem
04a8b49177 Quick changes for CHOW 2024-03-04 08:46:12 -05:00
Scott Idem
63990bb36a More changes based on feedback 2024-03-03 19:52:42 -05:00
Scott Idem
60f6386415 Changes based on feedback from Jordan (and Erin) 2024-03-03 19:22:44 -05:00
Scott Idem
7051cb92d5 Event presenter now has a slug directory 2024-03-03 12:51:14 -05:00
Scott Idem
64589ec11c Too many changes. Getting ready to show Jordan. 2024-03-03 12:31:32 -05:00
Scott Idem
1b12cd4aec Lots of bug fixes. Lots of clean up. Things work more consitently. 2024-03-02 20:54:45 -05:00
Scott Idem
4db9e68543 A lot of little changes everywhere. Sorry... 2024-03-02 20:09:25 -05:00
Scott Idem
0dbf869d5d Work on file related 2024-03-02 11:28:13 -05:00
Scott Idem
e69ff969f5 Walking away 2024-03-01 19:15:22 -05:00
Scott Idem
ff90fa5287 Done for reals... 2024-03-01 19:10:26 -05:00
Scott Idem
f09577d1d5 Done for the night... 2024-03-01 19:02:05 -05:00
Scott Idem
9fe4c51a67 Wrapping up for Friday night 2024-03-01 18:55:26 -05:00
Scott Idem
f4ed04497e Style clean up. A lot! Almost ready for CHOW going live. 2024-03-01 16:17:02 -05:00
Scott Idem
b21f9c0437 Wrapping up for the night. Mostly good for demo tomorrow morning. 2024-02-29 20:24:08 -05:00
Scott Idem
873e6d9f9a General clean up. Presenter form submission now works better. Need to do the same for the sponsorships submission form. 2024-02-29 16:14:31 -05:00
Scott Idem
e713313aca Bug fix for null bio field 2024-02-29 14:49:24 -05:00
Scott Idem
addadacc47 Getting ready for CHOW 2024 demo call tomorrow 2024-02-29 14:37:37 -05:00
Scott Idem
9310aac4d2 Button fix 2024-02-28 21:47:57 -05:00
Scott Idem
2c7e7ca027 Will now pull in agreements and accommations questions 2024-02-28 21:17:09 -05:00
Scott Idem
713fcb3c62 Bug fixes. Style setting improvements. 2024-02-28 15:45:02 -05:00
Scott Idem
00a28588b7 Wrapping up for the day 2024-02-27 20:21:02 -05:00
Scott Idem
ed97cba7a6 General clean up of code. Starting to wrap up for the night. 2024-02-27 19:20:21 -05:00
Scott Idem
714642380e Cleaning up code and making everything look better. 2024-02-27 18:38:46 -05:00
Scott Idem
22efa3fd96 Made the closing of the modals cleaner 2024-02-27 17:04:03 -05:00
Scott Idem
c93d84f3c3 Sponsorships and Speakers are working and looking pretty well. Other general clean up. 2024-02-27 16:50:37 -05:00
Scott Idem
9540aefd50 Finally got things working. Store act odd when being set under layout.ts? 2024-02-26 21:04:17 -05:00
Scott Idem
060c0500d3 General clean up. No working on the new event presenter components. 2024-02-26 15:03:01 -05:00
Scott Idem
740baa689e Need to work on not havnig the account ID set 2024-02-22 22:16:49 -05:00
Scott Idem
02f693c13e Making the loading a bit more efficient and cleaner 2024-02-22 20:28:29 -05:00
Scott Idem
d1328eb67c Added the access code component. Improved layout. General clean up and improvements. 2024-02-22 17:21:22 -05:00
Scott Idem
5a13852432 Wrapping up programming for tonight. Ready for CHOW demo? 2024-02-20 19:07:09 -05:00
Scott Idem
d51d059535 Finally got things mostly working. 2024-02-20 18:05:18 -05:00
Scott Idem
5bb9134641 I need to stop for the night. 2024-02-19 19:37:03 -05:00
Scott Idem
3403210efd This is the first commit of the day. It is probably the last. Lots of general prep for a demo. 2024-02-19 18:28:55 -05:00
Scott Idem
6f0680f282 Good first draft. Done for the night! 2024-02-16 22:15:54 -05:00
Scott Idem
bab68af7dc Making progress on pulling this together. 2024-02-16 21:38:41 -05:00
Scott Idem
9958724aaa I should have saved this long ago. Lots of changes. Learning a lot as well! 2024-02-16 20:12:19 -05:00
Scott Idem
cb9bd1648c Done for the night! 2024-02-15 19:19:01 -05:00
Scott Idem
a3d4354ef4 This is a good start. Many key features are working again!!! 2024-02-15 18:53:26 -05:00
Scott Idem
19f9983c9a Most things are working in the template now. 2024-02-15 11:55:42 -05:00
Scott Idem
17d99d080c Starting a new template using Svelte, SvelteKit, Tailwind, and Skeleton. 2024-02-15 09:49:35 -05:00
Scott Idem
ccbb783378 Variouu changes from a few days ago. 2024-02-15 09:20:57 -05:00
Scott Idem
970e7567fc More work on The Hub 2024-02-09 18:38:17 -05:00
Scott Idem
7f6f063f00 Work on the new Hub to manage the header, footer, menu, quick access, etc 2024-02-09 18:24:07 -05:00
Scott Idem
7775b88b35 General clean up of the new AE Sponsorships app. Making it portable too. 2024-02-08 17:51:38 -05:00
Scott Idem
06e0c98e68 Lots of clean up to get Sponsorships working. Need to add the edit next. 2024-02-07 18:23:15 -05:00
Scott Idem
143265ed9e Creating for AE "Sponsorships". Update file timestamps and remove unused files. Also switched to Svelte with Vite. 2024-02-06 18:23:01 -05:00
879 changed files with 58378 additions and 4264 deletions

View File

@@ -1,5 +1,5 @@
[Dolphin]
Timestamp=2021,7,8,11,31,30.712
Timestamp=2024,8,7,10,25,9.632
Version=4
ViewMode=1

13
.eslintignore Normal file
View File

@@ -0,0 +1,13 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

31
.eslintrc.cjs Normal file
View File

@@ -0,0 +1,31 @@
/** @type { import("eslint").Linter.Config } */
module.exports = {
root: true,
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:svelte/recommended',
'prettier'
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020,
extraFileExtensions: ['.svelte']
},
env: {
browser: true,
es2017: true,
node: true
},
overrides: [
{
files: ['*.svelte'],
parser: 'svelte-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser'
}
}
]
};

25
.gitignore vendored
View File

@@ -1,4 +1,23 @@
/node_modules/
/public/build/
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
# Backups and archives
*.bak
*.tar.gz

1
.npmrc Normal file
View File

@@ -0,0 +1 @@
engine-strict=true

4
.prettierignore Normal file
View File

@@ -0,0 +1,4 @@
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

8
.prettierrc Normal file
View File

@@ -0,0 +1,8 @@
{
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}

View File

@@ -1,3 +0,0 @@
{
"recommendations": ["svelte.svelte-vscode"]
}

120
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,120 @@
{
"prettier.documentSelectors": [
"**/*.svelte"
],
"tailwindCSS.classAttributes": [
"class",
"accent",
"active",
"animIndeterminate",
"aspectRatio",
"background",
"badge",
"bgBackdrop",
"bgDark",
"bgDrawer",
"bgLight",
"blur",
"border",
"button",
"buttonAction",
"buttonBack",
"buttonClasses",
"buttonComplete",
"buttonDismiss",
"buttonNeutral",
"buttonNext",
"buttonPositive",
"buttonTextCancel",
"buttonTextConfirm",
"buttonTextFirst",
"buttonTextLast",
"buttonTextNext",
"buttonTextPrevious",
"buttonTextSubmit",
"caretClosed",
"caretOpen",
"chips",
"color",
"controlSeparator",
"controlVariant",
"cursor",
"display",
"element",
"fill",
"fillDark",
"fillLight",
"flex",
"flexDirection",
"gap",
"gridColumns",
"height",
"hover",
"inactive",
"indent",
"justify",
"meter",
"padding",
"position",
"regionAnchor",
"regionBackdrop",
"regionBody",
"regionCaption",
"regionCaret",
"regionCell",
"regionChildren",
"regionChipList",
"regionChipWrapper",
"regionCone",
"regionContent",
"regionControl",
"regionDefault",
"regionDrawer",
"regionFoot",
"regionFootCell",
"regionFooter",
"regionHead",
"regionHeadCell",
"regionHeader",
"regionIcon",
"regionInput",
"regionInterface",
"regionInterfaceText",
"regionLabel",
"regionLead",
"regionLegend",
"regionList",
"regionListItem",
"regionNavigation",
"regionPage",
"regionPanel",
"regionRowHeadline",
"regionRowMain",
"regionSummary",
"regionSymbol",
"regionTab",
"regionTrail",
"ring",
"rounded",
"select",
"shadow",
"slotDefault",
"slotFooter",
"slotHeader",
"slotLead",
"slotMessage",
"slotMeta",
"slotPageContent",
"slotPageFooter",
"slotPageHeader",
"slotSidebarLeft",
"slotSidebarRight",
"slotTrail",
"spacing",
"text",
"track",
"transition",
"width",
"zIndex"
]
}

176
README.md
View File

@@ -1,105 +1,117 @@
*Looking for a shareable component template? Go here --> [sveltejs/component-template](https://github.com/sveltejs/component-template)*
# One Sky IT's SvelteKit Template
---
# svelte app
# Current Modules
## AE Events - Speakers (/events_speakers)
### Components
* +page.svelte - The main page for the Events - Speakers module
* 10_edit_modal__event_presenter_obj.svelte - The modal for editing a presenter
* 10_list__event_presenter_obj.svelte - The list of presenters/speakers
* 10_view_modal__event_presenter_obj.svelte - The modal for viewing a presenter
#### [slug]
* +page.svelte - The main page for the presenter ID [slug]
This is a project template for [Svelte](https://svelte.dev) apps. It lives at https://github.com/sveltejs/template.
## AE Sponsorships (/sponsorships)
* +page.svelte - The main page for the Sponsorships module
* 10_edit_modal__sponsorship_obj.svelte - The modal for editing a sponsorship
* 10_list__sponsorship_obj.svelte - The list of sponsorships
* 10_view_modal__sponsorship_obj.svelte - The modal for viewing a sponsorship
#### [slug]
* +page.svelte - The main page for the sponsorship ID [slug]
To create a new project based on this template using [degit](https://github.com/Rich-Harris/degit):
# Future Modules
## AE Events - Badges (/events_badges)
* +page.svelte - The main page for the Events - Badges module
* 10_list__event_badge_obj.svelte - The list of badges
* 10_view_modal__event_badge_obj.svelte - The modal for viewing a badge
## AE Events - Exhibit Leads (/events_exhibit_leads)
## AE Events - Presentation Management (/events_pres_mgmt)
# How to build and deploy SvelteKit:
Copy the contents of the "build" directory to ./npm_deploy/build/
```bash
npx degit sveltejs/template svelte-app
cd svelte-app
npm run build
```
*Note that you will need to have [Node.js](https://nodejs.org) installed.*
## Get started
Install the dependencies...
If this is just a quick build update then only the build directory needs to be copied (rsync).
```bash
cd svelte-app
npm install
rsync -vhrz --exclude 'node_modules' ~/OSIT_dev/ae_app_svelte_tailwind_skeleton/build/ ~/OSIT_dev/ae_env_node_app/npm_deploy/build/ --delete
rsync -vhrz ~/OSIT_dev/ae_env_node_app/npm_deploy/build/ scott@linode.oneskyit.com:/srv/env/prod_aether_sveltekit/npm_deploy/build/ --delete
```
...then start [Rollup](https://rollupjs.org):
If this includes package updates we need to copy the new package.json. Manually copy the new package.json file to ./npm_deploy/. This also needs to be copied to the server.
```bash
# copy/paste, rsync, or cp
```
Run the --omit dev to clear out the node_modules directory. Copy the root node_modules directory to ./npm_deploy/build/node_modules/ after running te omit dev command.
```bash
npm ci --omit dev
```
Everything should be ready to run on the development server and production server.
# Rebuild the node_modules directory and manually install extra Svelte packages
Run the npm update to fix the node_modules directory and package.json
```bash
npm update
```
Other installs?:
Are both still needed? I know at least one of these is. 2024-07-23
```bash
npm install --save-dev svelte-highlight
npm install --save-dev typescript-svelte-plugin
```
# Set up and run
## Build
## Environment file
# create-svelte
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).
## Creating a project
If you're seeing this, you've probably already done this step. Congrats!
```bash
# create a new project in the current directory
npm create svelte@latest
# create a new project in my-app
npm create svelte@latest my-app
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
Navigate to [localhost:5000](http://localhost:5000). You should see your app running. Edit a component file in `src`, save it, and reload the page to see your changes.
## Building
By default, the server will only respond to requests from localhost. To allow connections from other computers, edit the `sirv` commands in package.json to include the option `--host 0.0.0.0`.
If you're using [Visual Studio Code](https://code.visualstudio.com/) we recommend installing the official extension [Svelte for VS Code](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). If you are using other editors you may need to install a plugin in order to get syntax highlighting and intellisense.
## Building and running in production mode
To create an optimised version of the app:
To create a production version of your app:
```bash
npm run build
```
You can run the newly built app with `npm run start`. This uses [sirv](https://github.com/lukeed/sirv), which is included in your package.json's `dependencies` so that the app will work when you deploy to platforms like [Heroku](https://heroku.com).
You can preview the production build with `npm run preview`.
## Single-page app mode
By default, sirv will only respond to requests that match files in `public`. This is to maximise compatibility with static fileservers, allowing you to deploy your app anywhere.
If you're building a single-page app (SPA) with multiple routes, sirv needs to be able to respond to requests for *any* path. You can make it so by editing the `"start"` command in package.json:
```js
"start": "sirv public --single"
```
## Using TypeScript
This template comes with a script to set up a TypeScript development environment, you can run it immediately after cloning the template with:
```bash
node scripts/setupTypeScript.js
```
Or remove the script via:
```bash
rm scripts/setupTypeScript.js
```
## Deploying to the web
### With [Vercel](https://vercel.com)
Install `vercel` if you haven't already:
```bash
npm install -g vercel
```
Then, from within your project folder:
```bash
cd public
vercel deploy --name my-project
```
### With [surge](https://surge.sh/)
Install `surge` if you haven't already:
```bash
npm install -g surge
```
Then, from within your project folder:
```bash
npm run build
surge public my-project.surge.sh
```
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.

View File

@@ -0,0 +1,14 @@
{
"folders": [
{
"path": "."
}
],
"settings": {
"cSpell.words": [
"filelist"
],
"git.autofetch": true,
"editor.defaultFormatter": "svelte.svelte-vscode"
}
}

103
osit_ae_theme_1.ts Normal file
View File

@@ -0,0 +1,103 @@
import type { CustomThemeConfig } from '@skeletonlabs/tw-plugin';
export const myCustomTheme: CustomThemeConfig = {
name: 'my-custom-theme',
properties: {
// =~= Theme Properties =~=
"--theme-font-family-base": `Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'`,
"--theme-font-family-heading": `Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'`,
"--theme-font-color-base": "0 0 0",
"--theme-font-color-dark": "255 255 255",
"--theme-rounded-base": "16px",
"--theme-rounded-container": "8px",
"--theme-border-base": "1px",
// =~= Theme On-X Colors =~=
"--on-primary": "0 0 0",
"--on-secondary": "0 0 0",
"--on-tertiary": "0 0 0",
"--on-success": "0 0 0",
"--on-warning": "0 0 0",
"--on-error": "0 0 0",
"--on-surface": "0 0 0",
// =~= Theme Colors =~=
// primary | #99c1f1
"--color-primary-50": "240 246 253", // #f0f6fd
"--color-primary-100": "235 243 252", // #ebf3fc
"--color-primary-200": "230 240 252", // #e6f0fc
"--color-primary-300": "214 230 249", // #d6e6f9
"--color-primary-400": "184 212 245", // #b8d4f5
"--color-primary-500": "153 193 241", // #99c1f1
"--color-primary-600": "138 174 217", // #8aaed9
"--color-primary-700": "115 145 181", // #7391b5
"--color-primary-800": "92 116 145", // #5c7491
"--color-primary-900": "75 95 118", // #4b5f76
// secondary | #8ff0a4
"--color-secondary-50": "238 253 241", // #eefdf1
"--color-secondary-100": "233 252 237", // #e9fced
"--color-secondary-200": "227 251 232", // #e3fbe8
"--color-secondary-300": "210 249 219", // #d2f9db
"--color-secondary-400": "177 245 191", // #b1f5bf
"--color-secondary-500": "143 240 164", // #8ff0a4
"--color-secondary-600": "129 216 148", // #81d894
"--color-secondary-700": "107 180 123", // #6bb47b
"--color-secondary-800": "86 144 98", // #569062
"--color-secondary-900": "70 118 80", // #467650
// tertiary | #f8e45c
"--color-tertiary-50": "254 251 231", // #fefbe7
"--color-tertiary-100": "254 250 222", // #fefade
"--color-tertiary-200": "253 248 214", // #fdf8d6
"--color-tertiary-300": "252 244 190", // #fcf4be
"--color-tertiary-400": "250 236 141", // #faec8d
"--color-tertiary-500": "248 228 92", // #f8e45c
"--color-tertiary-600": "223 205 83", // #dfcd53
"--color-tertiary-700": "186 171 69", // #baab45
"--color-tertiary-800": "149 137 55", // #958937
"--color-tertiary-900": "122 112 45", // #7a702d
// success | #33d17a
"--color-success-50": "224 248 235", // #e0f8eb
"--color-success-100": "214 246 228", // #d6f6e4
"--color-success-200": "204 244 222", // #ccf4de
"--color-success-300": "173 237 202", // #adedca
"--color-success-400": "112 223 162", // #70dfa2
"--color-success-500": "51 209 122", // #33d17a
"--color-success-600": "46 188 110", // #2ebc6e
"--color-success-700": "38 157 92", // #269d5c
"--color-success-800": "31 125 73", // #1f7d49
"--color-success-900": "25 102 60", // #19663c
// warning | #ffa348
"--color-warning-50": "255 241 228", // #fff1e4
"--color-warning-100": "255 237 218", // #ffedda
"--color-warning-200": "255 232 209", // #ffe8d1
"--color-warning-300": "255 218 182", // #ffdab6
"--color-warning-400": "255 191 127", // #ffbf7f
"--color-warning-500": "255 163 72", // #ffa348
"--color-warning-600": "230 147 65", // #e69341
"--color-warning-700": "191 122 54", // #bf7a36
"--color-warning-800": "153 98 43", // #99622b
"--color-warning-900": "125 80 35", // #7d5023
// error | #f66151
"--color-error-50": "254 231 229", // #fee7e5
"--color-error-100": "253 223 220", // #fddfdc
"--color-error-200": "253 216 212", // #fdd8d4
"--color-error-300": "251 192 185", // #fbc0b9
"--color-error-400": "249 144 133", // #f99085
"--color-error-500": "246 97 81", // #f66151
"--color-error-600": "221 87 73", // #dd5749
"--color-error-700": "185 73 61", // #b9493d
"--color-error-800": "148 58 49", // #943a31
"--color-error-900": "121 48 40", // #793028
// surface | #deddda
"--color-surface-50": "250 250 249", // #fafaf9
"--color-surface-100": "248 248 248", // #f8f8f8
"--color-surface-200": "247 247 246", // #f7f7f6
"--color-surface-300": "242 241 240", // #f2f1f0
"--color-surface-400": "232 231 229", // #e8e7e5
"--color-surface-500": "222 221 218", // #deddda
"--color-surface-600": "200 199 196", // #c8c7c4
"--color-surface-700": "167 166 164", // #a7a6a4
"--color-surface-800": "133 133 131", // #858583
"--color-surface-900": "109 108 107", // #6d6c6b
}
}

103
osit_ae_theme_2.ts Normal file
View File

@@ -0,0 +1,103 @@
import type { CustomThemeConfig } from '@skeletonlabs/tw-plugin';
export const myCustomTheme: CustomThemeConfig = {
name: 'my-custom-theme',
properties: {
// =~= Theme Properties =~=
"--theme-font-family-base": `Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'`,
"--theme-font-family-heading": `Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'`,
"--theme-font-color-base": "0 0 0",
"--theme-font-color-dark": "255 255 255",
"--theme-rounded-base": "16px",
"--theme-rounded-container": "8px",
"--theme-border-base": "1px",
// =~= Theme On-X Colors =~=
"--on-primary": "0 0 0",
"--on-secondary": "0 0 0",
"--on-tertiary": "0 0 0",
"--on-success": "0 0 0",
"--on-warning": "0 0 0",
"--on-error": "0 0 0",
"--on-surface": "0 0 0",
// =~= Theme Colors =~=
// primary | #62a0ea
"--color-primary-50": "231 241 252", // #e7f1fc
"--color-primary-100": "224 236 251", // #e0ecfb
"--color-primary-200": "216 231 250", // #d8e7fa
"--color-primary-300": "192 217 247", // #c0d9f7
"--color-primary-400": "145 189 240", // #91bdf0
"--color-primary-500": "98 160 234", // #62a0ea
"--color-primary-600": "88 144 211", // #5890d3
"--color-primary-700": "74 120 176", // #4a78b0
"--color-primary-800": "59 96 140", // #3b608c
"--color-primary-900": "48 78 115", // #304e73
// secondary | #99c1f1
"--color-secondary-50": "240 246 253", // #f0f6fd
"--color-secondary-100": "235 243 252", // #ebf3fc
"--color-secondary-200": "230 240 252", // #e6f0fc
"--color-secondary-300": "214 230 249", // #d6e6f9
"--color-secondary-400": "184 212 245", // #b8d4f5
"--color-secondary-500": "153 193 241", // #99c1f1
"--color-secondary-600": "138 174 217", // #8aaed9
"--color-secondary-700": "115 145 181", // #7391b5
"--color-secondary-800": "92 116 145", // #5c7491
"--color-secondary-900": "75 95 118", // #4b5f76
// tertiary | #f8e45c
"--color-tertiary-50": "254 251 231", // #fefbe7
"--color-tertiary-100": "254 250 222", // #fefade
"--color-tertiary-200": "253 248 214", // #fdf8d6
"--color-tertiary-300": "252 244 190", // #fcf4be
"--color-tertiary-400": "250 236 141", // #faec8d
"--color-tertiary-500": "248 228 92", // #f8e45c
"--color-tertiary-600": "223 205 83", // #dfcd53
"--color-tertiary-700": "186 171 69", // #baab45
"--color-tertiary-800": "149 137 55", // #958937
"--color-tertiary-900": "122 112 45", // #7a702d
// success | #33d17a
"--color-success-50": "224 248 235", // #e0f8eb
"--color-success-100": "214 246 228", // #d6f6e4
"--color-success-200": "204 244 222", // #ccf4de
"--color-success-300": "173 237 202", // #adedca
"--color-success-400": "112 223 162", // #70dfa2
"--color-success-500": "51 209 122", // #33d17a
"--color-success-600": "46 188 110", // #2ebc6e
"--color-success-700": "38 157 92", // #269d5c
"--color-success-800": "31 125 73", // #1f7d49
"--color-success-900": "25 102 60", // #19663c
// warning | #ffa348
"--color-warning-50": "255 241 228", // #fff1e4
"--color-warning-100": "255 237 218", // #ffedda
"--color-warning-200": "255 232 209", // #ffe8d1
"--color-warning-300": "255 218 182", // #ffdab6
"--color-warning-400": "255 191 127", // #ffbf7f
"--color-warning-500": "255 163 72", // #ffa348
"--color-warning-600": "230 147 65", // #e69341
"--color-warning-700": "191 122 54", // #bf7a36
"--color-warning-800": "153 98 43", // #99622b
"--color-warning-900": "125 80 35", // #7d5023
// error | #f66151
"--color-error-50": "254 231 229", // #fee7e5
"--color-error-100": "253 223 220", // #fddfdc
"--color-error-200": "253 216 212", // #fdd8d4
"--color-error-300": "251 192 185", // #fbc0b9
"--color-error-400": "249 144 133", // #f99085
"--color-error-500": "246 97 81", // #f66151
"--color-error-600": "221 87 73", // #dd5749
"--color-error-700": "185 73 61", // #b9493d
"--color-error-800": "148 58 49", // #943a31
"--color-error-900": "121 48 40", // #793028
// surface | #deddda
"--color-surface-50": "250 250 249", // #fafaf9
"--color-surface-100": "248 248 248", // #f8f8f8
"--color-surface-200": "247 247 246", // #f7f7f6
"--color-surface-300": "242 241 240", // #f2f1f0
"--color-surface-400": "232 231 229", // #e8e7e5
"--color-surface-500": "222 221 218", // #deddda
"--color-surface-600": "200 199 196", // #c8c7c4
"--color-surface-700": "167 166 164", // #a7a6a4
"--color-surface-800": "133 133 131", // #858583
"--color-surface-900": "109 108 107", // #6d6c6b
}
}

103
osit_ae_theme_3.ts Normal file
View File

@@ -0,0 +1,103 @@
import type { CustomThemeConfig } from '@skeletonlabs/tw-plugin';
export const myCustomTheme: CustomThemeConfig = {
name: 'my-custom-theme',
properties: {
// =~= Theme Properties =~=
"--theme-font-family-base": `Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'`,
"--theme-font-family-heading": `Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'`,
"--theme-font-color-base": "0 0 0",
"--theme-font-color-dark": "255 255 255",
"--theme-rounded-base": "16px",
"--theme-rounded-container": "8px",
"--theme-border-base": "1px",
// =~= Theme On-X Colors =~=
"--on-primary": "0 0 0",
"--on-secondary": "0 0 0",
"--on-tertiary": "0 0 0",
"--on-success": "0 0 0",
"--on-warning": "0 0 0",
"--on-error": "0 0 0",
"--on-surface": "0 0 0",
// =~= Theme Colors =~=
// primary | #3584e4
"--color-primary-50": "225 237 251", // #e1edfb
"--color-primary-100": "215 230 250", // #d7e6fa
"--color-primary-200": "205 224 248", // #cde0f8
"--color-primary-300": "174 206 244", // #aecef4
"--color-primary-400": "114 169 236", // #72a9ec
"--color-primary-500": "53 132 228", // #3584e4
"--color-primary-600": "48 119 205", // #3077cd
"--color-primary-700": "40 99 171", // #2863ab
"--color-primary-800": "32 79 137", // #204f89
"--color-primary-900": "26 65 112", // #1a4170
// secondary | #99c1f1
"--color-secondary-50": "240 246 253", // #f0f6fd
"--color-secondary-100": "235 243 252", // #ebf3fc
"--color-secondary-200": "230 240 252", // #e6f0fc
"--color-secondary-300": "214 230 249", // #d6e6f9
"--color-secondary-400": "184 212 245", // #b8d4f5
"--color-secondary-500": "153 193 241", // #99c1f1
"--color-secondary-600": "138 174 217", // #8aaed9
"--color-secondary-700": "115 145 181", // #7391b5
"--color-secondary-800": "92 116 145", // #5c7491
"--color-secondary-900": "75 95 118", // #4b5f76
// tertiary | #f8e45c
"--color-tertiary-50": "254 251 231", // #fefbe7
"--color-tertiary-100": "254 250 222", // #fefade
"--color-tertiary-200": "253 248 214", // #fdf8d6
"--color-tertiary-300": "252 244 190", // #fcf4be
"--color-tertiary-400": "250 236 141", // #faec8d
"--color-tertiary-500": "248 228 92", // #f8e45c
"--color-tertiary-600": "223 205 83", // #dfcd53
"--color-tertiary-700": "186 171 69", // #baab45
"--color-tertiary-800": "149 137 55", // #958937
"--color-tertiary-900": "122 112 45", // #7a702d
// success | #33d17a
"--color-success-50": "224 248 235", // #e0f8eb
"--color-success-100": "214 246 228", // #d6f6e4
"--color-success-200": "204 244 222", // #ccf4de
"--color-success-300": "173 237 202", // #adedca
"--color-success-400": "112 223 162", // #70dfa2
"--color-success-500": "51 209 122", // #33d17a
"--color-success-600": "46 188 110", // #2ebc6e
"--color-success-700": "38 157 92", // #269d5c
"--color-success-800": "31 125 73", // #1f7d49
"--color-success-900": "25 102 60", // #19663c
// warning | #ffa348
"--color-warning-50": "255 241 228", // #fff1e4
"--color-warning-100": "255 237 218", // #ffedda
"--color-warning-200": "255 232 209", // #ffe8d1
"--color-warning-300": "255 218 182", // #ffdab6
"--color-warning-400": "255 191 127", // #ffbf7f
"--color-warning-500": "255 163 72", // #ffa348
"--color-warning-600": "230 147 65", // #e69341
"--color-warning-700": "191 122 54", // #bf7a36
"--color-warning-800": "153 98 43", // #99622b
"--color-warning-900": "125 80 35", // #7d5023
// error | #f66151
"--color-error-50": "254 231 229", // #fee7e5
"--color-error-100": "253 223 220", // #fddfdc
"--color-error-200": "253 216 212", // #fdd8d4
"--color-error-300": "251 192 185", // #fbc0b9
"--color-error-400": "249 144 133", // #f99085
"--color-error-500": "246 97 81", // #f66151
"--color-error-600": "221 87 73", // #dd5749
"--color-error-700": "185 73 61", // #b9493d
"--color-error-800": "148 58 49", // #943a31
"--color-error-900": "121 48 40", // #793028
// surface | #deddda
"--color-surface-50": "250 250 249", // #fafaf9
"--color-surface-100": "248 248 248", // #f8f8f8
"--color-surface-200": "247 247 246", // #f7f7f6
"--color-surface-300": "242 241 240", // #f2f1f0
"--color-surface-400": "232 231 229", // #e8e7e5
"--color-surface-500": "222 221 218", // #deddda
"--color-surface-600": "200 199 196", // #c8c7c4
"--color-surface-700": "167 166 164", // #a7a6a4
"--color-surface-800": "133 133 131", // #858583
"--color-surface-900": "109 108 107", // #6d6c6b
}
}

6970
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,31 +1,59 @@
{
"name": "svelte-app",
"version": "1.0.0",
"name": "ae-app-svelte-tailwind-skeleton",
"version": "0.1.1",
"private": true,
"scripts": {
"build": "rollup -c",
"dev": "rollup -c -w",
"start": "sirv public --single --port 5555",
"validate": "svelte-check"
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"test": "npm run test:integration && npm run test:unit",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check . && eslint .",
"format": "prettier --write .",
"test:integration": "playwright test",
"test:unit": "vitest"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^17.0.0",
"@rollup/plugin-node-resolve": "^11.0.0",
"@rollup/plugin-typescript": "^8.0.0",
"@tsconfig/svelte": "^1.0.0",
"rollup": "^2.3.4",
"rollup-plugin-css-only": "^3.1.0",
"rollup-plugin-livereload": "^2.0.0",
"rollup-plugin-svelte": "^7.0.0",
"rollup-plugin-terser": "^7.0.0",
"svelte": "^3.0.0",
"svelte-check": "^1.0.0",
"svelte-preprocess": "^4.0.0",
"tslib": "^2.0.0",
"typescript": "^4.0.0"
"@playwright/test": "^1.28.1",
"@skeletonlabs/skeleton": "^2.8.0",
"@skeletonlabs/tw-plugin": "^0.4.0",
"@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/adapter-node": "^5.0.0",
"@sveltejs/adapter-static": "^3.0.1",
"@sveltejs/kit": "^2.5.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"@tailwindcss/forms": "0.5.7",
"@tailwindcss/typography": "^0.5.10",
"@types/eslint": "^8.0.0",
"@types/node": "^20.11.18",
"@typescript-eslint/eslint-plugin": "^7.16.0",
"@typescript-eslint/parser": "^7.16.0",
"autoprefixer": "^10.4.20",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.24.0",
"highlight.js": "^11.10.0",
"postcss": "^8.4.41",
"prettier": "^3.1.1",
"prettier-plugin-svelte": "^3.1.2",
"svelte": "^4.2.0",
"svelte-check": "^3.6.0",
"svelte-highlight": "^7.7.0",
"tailwindcss": "^3.4.10",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"typescript-svelte-plugin": "^0.3.39",
"vite": "^5.1.0",
"vite-plugin-tailwind-purgecss": "^0.3.3",
"vitest": "^2.0.2"
},
"type": "module",
"dependencies": {
"axios": "^0.21.1",
"sirv-cli": "^1.0.0"
"@floating-ui/dom": "^1.6.3",
"axios": "^1.6.7",
"dayjs": "^1.11.10",
"dexie": "^4.0.1-beta.14",
"html5-qrcode": "^2.3.8"
}
}

12
playwright.config.ts Normal file
View File

@@ -0,0 +1,12 @@
import type { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
webServer: {
command: 'npm run build && npm run preview',
port: 4173
},
testDir: 'tests',
testMatch: /(.+\.)?(test|spec)\.[jt]s/
};
export default config;

6
postcss.config.cjs Normal file
View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

@@ -1,88 +0,0 @@
html, body {
position: relative;
/* width: 100%; */
height: 100%;
max-width: 100%;
}
body {
/* color: #333;
margin: 0;
padding: 8px;
box-sizing: border-box;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; */
}
h1 {
color: hsla(0, 0%, 5%, 1);
/*text-transform: uppercase;*/
/* font-size: 4rem; */
/* font-weight: 100; */
}
h2 {
color: hsla(0, 0%, 10%, 1);
/*text-transform: uppercase;*/
/* font-size: 4rem; */
/* font-weight: 100; */
}
a {
/* color: rgb(0,100,200);
text-decoration: none; */
}
a:hover {
/* text-decoration: underline; */
}
a:visited {
/* color: rgb(0,80,160); */
}
label {
/* display: block; */
}
input, button, select, textarea {
/* font-family: inherit;
font-size: inherit;
-webkit-padding: 0.4rem 0;
padding: 0.4rem;
margin: 0 0 0.5rem 0;
box-sizing: border-box;
border: 1px solid #ccc;
border-radius: 2px; */
}
input:disabled {
color: hsla(0, 0%, 50%, 1);
}
button {
/* color: #333;
background-color: #f4f4f4;
outline: none; */
}
button:disabled {
color: hsla(0, 0%, 50%, 1);
}
button:not(:disabled):active {
background-color: hsla(0, 0%, 50%, 1);
}
button:focus {
/* border-color: #666; */
}
button:hover {
/* background-color: green; */
}
#my_body {
/* outline: solid thin red; */
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -1,35 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<title>Index - Svelte</title>
<link rel='icon' type='image/png' href='/favicon.png'>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.2/css/all.css">
<link rel='stylesheet' href='https://static.oneskyit.com/css/global.css'>
<link rel='stylesheet' href='/app_global.css'>
<link rel='stylesheet' href='/build/bundle.css'>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.9.4/dayjs.min.js" integrity="sha512-XZSHSEFj4QeE0G4pwy4tToyAhF2VXoEcF9CP0t1PSZMP2XHhEEB9PjM9knsdzcEKbi6GRMazdt8tJadz0JTKIQ==" crossorigin="anonymous"></script>
<script defer src='https://static.oneskyit.com/js/utilities.js'></script>
<script defer src='/build/bundle.js'></script>
</head>
<body>
<header><h1>Index - Dev Svelte App</h1></header>
<main>
<a href="log_client_viewing">log_client_viewing</a>
<a href="membership_member_manage">membership_member_manage</a>
<a href="user_person">user_person</a>
<div id="test_container" class="svelte_container">
</div>
</main>
<footer>
This is the footer
</footer>
</body>
</html>

View File

@@ -1,32 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<title>Log Client Viewing - Dev Svelte App</title>
<link rel='icon' type='image/png' href='/favicon.png'>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.2/css/all.css">
<link rel='stylesheet' href='https://static.oneskyit.com/css/global.css'>
<link rel='stylesheet' href='/app_global.css'>
<link rel='stylesheet' href='/build/bundle.css'>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.9.4/dayjs.min.js" integrity="sha512-XZSHSEFj4QeE0G4pwy4tToyAhF2VXoEcF9CP0t1PSZMP2XHhEEB9PjM9knsdzcEKbi6GRMazdt8tJadz0JTKIQ==" crossorigin="anonymous"></script>
<script defer src='https://static.oneskyit.com/js/utilities.js'></script>
<script defer src='/build/bundle.js'></script>
<script>
let account_id = 'TblpWmPauKw';
</script>
</head>
<body>
<header><h1>Log Client Viewing - Dev Svelte App</h1></header>
<main>
<div id="log_client_viewing_list_container" class="svelte_container">
</div>
</main>
</body>
</html>

View File

@@ -1,33 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<title>Membership Member Manage - Dev Svelte App</title>
<link rel='icon' type='image/png' href='/favicon.png'>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.2/css/all.css">
<link rel='stylesheet' href='https://static.oneskyit.com/css/global.css'>
<link rel='stylesheet' href='/app_global.css'>
<link rel='stylesheet' href='/build/bundle.css'>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.9.4/dayjs.min.js" integrity="sha512-XZSHSEFj4QeE0G4pwy4tToyAhF2VXoEcF9CP0t1PSZMP2XHhEEB9PjM9knsdzcEKbi6GRMazdt8tJadz0JTKIQ==" crossorigin="anonymous"></script>
<script defer src='https://static.oneskyit.com/js/utilities.js'></script>
<script defer src='/build/bundle.js'></script>
<script>
let account_id = '_PRgRxSkzu-Xg-V4Ft1RGg';
let membership_member_id = '6jMd9WwnMbs';
</script>
</head>
<body>
<header><h1>Membership Member Manage - Dev Svelte App</h1></header>
<main>
<div id="membership_member_manage_container" class="svelte_container">
</div>
</main>
</body>
</html>

View File

@@ -1,36 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<title>User Person - Dev Svelte App</title>
<link rel='icon' type='image/png' href='/favicon.png'>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.2/css/all.css">
<link rel='stylesheet' href='https://static.oneskyit.com/css/global.css'>
<link rel='stylesheet' href='/app_global.css'>
<link rel='stylesheet' href='/build/bundle.css'>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.9.4/dayjs.min.js" integrity="sha512-XZSHSEFj4QeE0G4pwy4tToyAhF2VXoEcF9CP0t1PSZMP2XHhEEB9PjM9knsdzcEKbi6GRMazdt8tJadz0JTKIQ==" crossorigin="anonymous"></script>
<script defer src='https://static.oneskyit.com/js/utilities.js'></script>
<script defer src='/build/bundle.js'></script>
<script>
let account_id = '_PRgRxSkzu-Xg-V4Ft1RGg';
let person_id = 'OfcrSXX_evI';
let user_id = 'VMvg8X3QnZM';
</script>
</head>
<body>
<header><h1>User Person - Dev Svelte App</h1></header>
<main>
<div id="user_container" class="svelte_container">
</div>
<div id="person_container" class="svelte_container">
</div>
</main>
</body>
</html>

View File

@@ -1,83 +0,0 @@
import svelte from 'rollup-plugin-svelte';
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';
import sveltePreprocess from 'svelte-preprocess';
import typescript from '@rollup/plugin-typescript';
import css from 'rollup-plugin-css-only';
const production = !process.env.ROLLUP_WATCH;
function serve() {
let server;
function toExit() {
if (server) server.kill(0);
}
return {
writeBundle() {
if (server) return;
server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
stdio: ['ignore', 'inherit', 'inherit'],
shell: true
});
process.on('SIGTERM', toExit);
process.on('exit', toExit);
}
};
}
export default {
input: 'src/main.ts',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/build/bundle.js'
},
plugins: [
svelte({
preprocess: sveltePreprocess({ sourceMap: !production }),
compilerOptions: {
// enable run-time checks when not in production
dev: !production
}
}),
// we'll extract any component CSS out into
// a separate file - better for performance
css({ output: 'bundle.css' }),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration -
// consult the documentation for details:
// https://github.com/rollup/plugins/tree/master/packages/commonjs
resolve({
browser: true,
dedupe: ['svelte']
}),
commonjs(),
typescript({
sourceMap: !production,
inlineSources: !production
}),
// In dev mode, call `npm run start` once
// the bundle has been generated
!production && serve(),
// Watch the `public` directory and refresh the
// browser on changes when not in production
!production && livereload('public'),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser()
],
watch: {
clearScreen: false
}
};

View File

@@ -1,21 +0,0 @@
<script lang="ts">
import Test from './test.svelte';
export let name: string;
</script>
<section>
<p>Name: {name}</p>
<Test />
</section>
<style>
section {
text-align: center;
}
p {
color: green;
}
</style>

View File

@@ -1,75 +0,0 @@
<script lang="ts">
export let name: string;
let count = 0;
function handleClick() {
count += 1;
}
let m = { x: 0, y: 0 };
function handle_mousemove(event) {
m.x = event.clientX;
m.y = event.clientY;
}
let first_name = '';
let last_name = '';
let full_name = 'Not Here';
$: full_name = first_name + ' ' + last_name;
let name_checked = false;
</script>
<main>
<input bind:value={first_name}>
<input bind:value={last_name}>
<label>Check me <input type=checkbox bind:checked={name_checked}></label>
<h1>Hello {full_name}!</h1>
{#if name_checked}
<p>Thank you. We will bombard your inbox and sell your personal details.</p>
{:else}
<p>You must opt in to continue. If you're not paying, you're the product.</p>
{/if}
<button disabled={!name_checked}>
Subscribe
</button>
<p>This is a new app using Svelte.</p>
<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
<div class="my_class">My fancy class!</div>
<div on:mousemove={handle_mousemove}>
The mouse position is {m.x} x {m.y}
</div>
</main>
<style>
main {
text-align: center;
padding: 1rem;
max-width: 240px;
margin: 0 auto;
}
h1 {
color: hsla(0, 50%, 50%, 1);
/*text-transform: uppercase;*/
font-size: 4rem;
font-weight: 100;
}
@media (min-width: 640px) {
main {
max-width: none;
}
}
</style>

View File

@@ -1,38 +0,0 @@
import axios from 'axios';
console.log('*** api_update.js ***');
var axios_fastapi = axios.create({
//baseURL: 'https://dev-fastapi.oneskyit.com',
//baseURL: 'http://fastapi.localhost:5005',
baseURL: 'http://192.168.32.20:5005',
/* other custom settings */
});
axios_fastapi.defaults.headers['Access-Control-Allow-Origin'] = '*';
axios_fastapi.defaults.headers['content-type'] = 'application/json';
axios_fastapi.defaults.headers['x-aether-api-key'] = 'aaabbbcccxxxyyyzzz';
axios_fastapi.defaults.headers['x-aether-api-token'] = 'aaabbbcccxxxyyyzzz';
axios_fastapi.defaults.headers['x-aether-api-expire-on'] = '';
axios_fastapi.defaults.headers['x-account-id'] = 'xxxyyyzzz111222333';
async function delete_object({axios=axios_fastapi, endpoint='', data=[]}) {
console.log('*** delete_object() ***');
console.log(data)
// https://stackoverflow.com/questions/51069552/axios-delete-request-with-body-and-headers
let response_data = await axios.delete(endpoint, { 'data': data }) // not just data?
.then(function (response) {
console.log(response.data);
return response.data;
})
.catch(function (error) {
console.log(error);
return error;
});
return response_data;
}
export default delete_object;

View File

@@ -1,52 +0,0 @@
import axios from 'axios';
console.log('*** api_update.js ***');
var axios_fastapi = axios.create({
baseURL: 'https://dev-fastapi.oneskyit.com',
// baseURL: 'http://fastapi.localhost:5005',
// baseURL: 'http://192.168.32.20:5005',
/* other custom settings */
});
axios_fastapi.defaults.headers['Access-Control-Allow-Origin'] = '*';
axios_fastapi.defaults.headers['content-type'] = 'application/json';
axios_fastapi.defaults.headers['x-aether-api-key'] = 'aaabbbcccxxxyyyzzz';
axios_fastapi.defaults.headers['x-aether-api-token'] = 'aaabbbcccxxxyyyzzz';
axios_fastapi.defaults.headers['x-aether-api-expire-on'] = '';
axios_fastapi.defaults.headers['x-account-id'] = 'xxxyyyzzz111222333';
async function get_object({axios=axios_fastapi, endpoint='', params=[], data=[], return_meta=false, force_li=false}) {
console.log('*** get_object() ***');
//console.log(endpoint);
//console.log(params);
//console.log(data);
//console.log(return_meta);
//console.log(force_li);
let response_data = await axios.get(endpoint, { params: params })
.then(function (response) {
console.log(response.data);
if (!Array.isArray(response.data['data']) && force_li) {
console.log('Forcing return as a list');
let return_data = [];
return_data.push(response.data['data']);
return return_data;
} else {
return response.data['data'];
}
//return response.data;
})
.catch(function (error) {
console.log(error.response);
if (error.response.status === 404) {
return null;
}
return error;
});
return response_data;
}
export default get_object;

View File

@@ -1,45 +0,0 @@
import axios from 'axios';
console.log('*** api_update.js ***');
var axios_fastapi = axios.create({
// baseURL: 'https://dev-fastapi.oneskyit.com',
baseURL: 'http://fastapi.localhost:5005',
// baseURL: 'http://192.168.32.20:5005',
/* other custom settings */
});
axios_fastapi.defaults.headers['Access-Control-Allow-Origin'] = '*';
axios_fastapi.defaults.headers['content-type'] = 'application/json';
axios_fastapi.defaults.headers['x-aether-api-key'] = 'aaabbbcccxxxyyyzzz';
axios_fastapi.defaults.headers['x-aether-api-token'] = 'aaabbbcccxxxyyyzzz';
axios_fastapi.defaults.headers['x-aether-api-expire-on'] = '';
axios_fastapi.defaults.headers['x-account-id'] = 'xxxyyyzzz111222333';
async function patch_object({axios=axios_fastapi, endpoint='', params=[], record=[], return_meta=false}) {
console.log('*** patch_object() ***');
//console.log(endpoint);
//console.log(params);
console.log(record);
//console.log(return_meta);
//console.log(force_li);
let response_data = await axios.patch(endpoint, record, { params: params })
.then(function (response) {
console.log(response.data);
return response.data['data'];
//return response.data;
})
.catch(function (error) {
console.log(error.response);
if (error.response.status === 404) {
return null;
}
return error;
});
return response_data;
}
export default patch_object;

View File

@@ -1,45 +0,0 @@
import axios from 'axios';
console.log('*** api_post.js ***');
var axios_fastapi = axios.create({
// baseURL: 'https://dev-fastapi.oneskyit.com',
baseURL: 'http://fastapi.localhost:5005',
// baseURL: 'http://192.168.32.20:5005',
/* other custom settings */
});
axios_fastapi.defaults.headers['Access-Control-Allow-Origin'] = '*';
axios_fastapi.defaults.headers['content-type'] = 'application/json';
axios_fastapi.defaults.headers['x-aether-api-key'] = 'aaabbbcccxxxyyyzzz';
axios_fastapi.defaults.headers['x-aether-api-token'] = 'aaabbbcccxxxyyyzzz';
axios_fastapi.defaults.headers['x-aether-api-expire-on'] = '';
axios_fastapi.defaults.headers['x-account-id'] = 'xxxyyyzzz111222333';
async function post_object({axios=axios_fastapi, endpoint='', record=[], return_meta=false}) {
console.log('*** post_object() ***');
//console.log(endpoint);
//console.log(params);
console.log(record);
//console.log(return_meta);
//console.log(force_li);
let response_data = await axios.post(endpoint, record)
.then(function (response) {
console.log(response.data);
return response.data['data'];
//return response.data;
})
.catch(function (error) {
console.log(error.response);
if (error.response.status === 404) {
return null;
}
return error;
});
return response_data;
}
export default post_object;

9
src/app.d.ts vendored Normal file
View File

@@ -0,0 +1,9 @@
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
// and what to do when importing types
declare namespace App {
// interface Locals {}
// interface PageData {}
// interface Error {}
// interface Platform {}
}

29
src/app.html Normal file
View File

@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en" class="light">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<link rel="manifest" href="%sveltekit.assets%/manifest.json">
<meta name="viewport" content="width=device-width" />
<title>OSIT's Aether System (&AElig;) - Built with SvelteKit</title>
<link rel="preconnect" href="https://fonts.gstatic.com">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Noto+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" integrity="sha512-1ycn6IcaQQ40/MKBW2W4Rhis/DbILU74C1vSrLJxCq57o941Ym01SwNsOMqvEBFlcgUa6xLiPY/NS5R+E6ztJQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<script>
</script>
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover" data-theme="my-custom-theme">
<div style="display: contents" class="h-full w-full overflow-hidden">%sveltekit.body%</div>
</body>
</html>

364
src/app.postcss Normal file
View File

@@ -0,0 +1,364 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@tailwind variants;
html,
body {
@apply h-full overflow-hidden;
/* font-family: 'Liberation Sans', sans-serif; */
/* font-family: 'Noto Sans', sans-serif; */
}
/* default theme */
/* @font-face {
font-family: 'Liberation Sans', sans-serif;
font-family: 'Noto Sans', sans-serif;
src: url('/fonts/liberation/LiberationSans-Regular.ttf');
src: url('/fonts/noto/NotoSans-Regular.ttf');
font-display: swap;
} */
/* modern theme */
@font-face {
font-family: 'Quicksand';
src: url('/fonts/Quicksand.ttf');
font-display: swap;
}
/* :root [data-theme='modern'] { */
/* --theme-rounded-base: 20px;
--theme-rounded-container: 4px; */
/* --theme-font-family-base: 'Liberation Sans', sans-serif; */
/* --theme-font-family-heading: 'Liberation Sans', sans-serif; */
/* } */
.card-footer {
border-top: 1px solid hsla(0, 0%, 0%, 0.5);
margin-top: 1em;
padding-top: 1em;
opacity: .5;
}
/* Tailwind: This "fixes" Tailwind's default group button styles that do not seem to allow hidding buttons. */
.btn-group a.hidden, .btn-group button.hidden {
display: none;
}
.ae_d_none {
display: none;
}
/* Allow content to scroll horizontal if too wide */
.ae_h_scrollfix {
max-width: 100%;
overflow-x: auto;
}
/* These helps with the Skeleton Tailwind modal utility. */
.ae_modal_scrollfix {
/* Allow modal content to scroll if it's too long */
overflow-y: auto;
max-height: 96vh;
/* max-height: 99%; */
}
.ae_debug {
/* A darker pink outline */
outline: thin dashed;
outline-color: hsla(0, 100%, 50%, 0.15);
/* A light pink background color */
background-color: hsla(0, 100%, 50%, 0.15);
}
.ae_debug:hover {
/* A darker pink outline */
outline-color: hsla(0, 100%, 50%, 0.50);
/* A light pink background color */
background-color: hsla(0, 100%, 50%, 0.40);
}
/* Deal with being in an iframe */
#appShell #shell-header.iframe {
display: none;
}
#appShell #shell-footer.iframe {
display: none;
}
/* Remove the background from the body in all cases */
/* body[data-theme] { */
/* background: none; */
/* background-image: none; */
/* } */
/* Remove the background from the body if using iframes */
/* body[data-theme]:has(#page.iframe) { */
/* background: none; */
/* background-image: none; */
/* background-image: url('https://static.oneskyit.com/c/CHOW/images/CHOW_2024_yellow_background.png'); */
/* background-size: cover; */
/* } */
main {
/* background: none;
background-color: hsla(0, 0%, 100%, 0.92); */
}
main>section {
background: none;
background-color: hsla(0, 0%, 100%, 0.92);
padding: .5em;
}
/* @media (min-width: 640px) {
main>div, main>section {
padding: 0;
max-width: 100%;
}
} */
/* @media (min-width: 768px) {
main>div, main>section {
padding: 0;
max-width: 100%;
}
} */
.ae_sponsorships {
/* background: none; */
/* background-color: hsla(0, 0%, 100%, 0.92); */
/* background-image: url('https://static.oneskyit.com/c/CHOW/images/CHOW_2024_yellow_background.png'); */
/* background-size: cover; */
}
pre.pre_wrap {
white-space: pre-wrap;
word-break: normal;
word-wrap: normal;
border: none;
max-width: 100%;
overflow-x: auto;
}
input.required {
/* border-right: solid medium var(--color-warning-500); */
/* color: var(--color-warning-500); */
}
input:required {
/* background-color: var(--alert-color-lightest); */
/* border: solid 2px red; */
/* outline: dashed thin var(--alert-color-lighter); */
/* border-right: solid medium var(--alert-color-mid); */
/* border-right: solid medium var(--warning-color-mid); */
/* border-right: solid medium var(--error-color-mid); */
}
/* input:required:hover {
background-color: var(--alert-color-lighter);
border-right: solid thick var(--alert-color-darker);
} */
/* input:required::before {
display: block;
content: '*';
color: var(--warning-color-darker);
top: 5px;
left: 5px;
} */
.input_required::after {
content: '*';
color: rgb(var(--color-error-500) / 0.9);
position: relative;
/* top: 0em; */
left: .25em;
}
/* Make the group a flex row by default */
/* div.btn-group { */
/* display: flex; */
/* gap: 0; */
/* flex-direction: row; */
/* justify-content: space-around; */
/* align-items: center; */
/* margin: 0;
padding: 0; */
/* } */
/* Make all button elements except for the the first button element not rounded on the left. */
/* Make all button elements except for the fhe last button element not rounded on the right. */
/* These helps with the Skeleton (Tailwind?) button group element. */
.btn-group button {
border-radius: 0;
border: none;
}
/* .md:btn-group button,
.lg:btn-group button {
border-radius: 0;
border: none;
} */
/* div.btn-group button:first-child {
border-top-left-radius: .25rem;
border-bottom-left-radius: .25rem;
}
div.btn-group button:last-child {
border-top-right-radius: .25rem;
border-bottom-right-radius: .25rem;
} */
.ae_obj_prop .label {
}
.ae_obj_prop .value {
font-weight: bold;
}
.ae_md_hide {
/* outline: medium dashed green; */
/* display: none; */
}
@media (max-width: 767px) {
.ae_md_hide {
/* outline: medium dashed red; */
display: none;
}
}
@media (min-width: 768px) {
.ae_lg_hide {
/* outline: medium dashed blue; */
display: none;
}
}
/* Use the div.ae_quick_modal_container to block background clicks when using the section.ae_quick_popover. */
div.ae_quick_modal_container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 100;
background-color: hsla(0, 0%, 0%, .5);
}
/* The section.ae_quick_popover should be above the rest of the content and centered on the page. */
section.ae_quick_popover {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 100;
background-color: hsla(0, 0%, 100%, .95);
padding: 1rem;
border-radius: .5rem;
box-shadow: 0 0 1rem hsla(0, 0%, 0%, .5);
min-height: 98%;
min-width: 98%;
}
section.ae_quick_popover_small {
position: fixed;
top: 1em;
left: 50%;
transform: translate(-50%, 0%);
z-index: 100;
background-color: hsla(0, 0%, 100%, .95);
padding: 1rem;
border-radius: .5rem;
box-shadow: 0 0 1rem hsla(0, 0%, 0%, .5);
min-height: 24rem;
max-height: 95%;
min-width: 50%;
max-width: 95%;
}
.fade_50 {
opacity: 0.5;
}
.fade_50:hover {
opacity: 1;
}
.auth_view_only {
display: none;
}
.ae_root--auth_access .auth_view_only {
display: initial;
}
img.qr_code {
/* outline: solid thin hsla(30, 100%, 50%, .1); */
/* width: 1.50in; */
}
img.qr_code:hover {
/* outline: solid thin green; */
/* width: 2.50in; */
}
img.qr_code:focus {
/* outline: solid thin red; */
/* width: 2.50in; */
}
.dim {
opacity: 0.5;
color: hsla(0, 0%, 50%, .95);
}
@media (max-width: 767px) {
.sk_header.hide_sm {
display: none;
}
.sk_header.show_sm {
display: initial;
}
.sk_header.show_md {
display: none;
}
}
@media (min-width: 768px) {
.sk_header.hide_md {
display: none;
}
.sk_header.show_md {
display: initial;
}
.sk_header.show_sm {
display: none;
}
}

View File

@@ -1,119 +0,0 @@
var template = {};
// NOTE address template section
template['address'] = {};
template['address']['id'] = { 'obj_type': 'address', 'obj_prop_name': 'id', 'type': 'hidden', 'placeholder': '', 'class_li': [], 'style': '', 'readonly': 'readonly', 'disabled': 'disabled', 'required': 'required', 'label': 'ID', 'label_class_li': [] };
template['address']['id_random'] = { 'obj_type': 'address', 'obj_prop_name': 'id_random', 'type': 'hidden', 'placeholder': '', 'class_li': [], 'style': '', 'readonly': 'readonly', 'disabled': 'disabled', 'required': 'required', 'label': 'ID random', 'label_class_li': [] };
template['address']['for_type'] = { 'obj_type': 'address', 'obj_prop_name': 'for_type', 'type': 'text', 'placeholder': 'For type', 'class': 'address.for_type', 'style': '', 'label': 'For type', 'label_class_li': [] };
template['address']['for_id'] = { 'obj_type': 'address', 'obj_prop_name': 'for_id', 'type': 'text', 'placeholder': 'For ID', 'class': 'address.for_id', 'style': '', 'label': 'For ID', 'label_class_li': [] };
template['address']['name'] = { 'obj_type': 'address', 'obj_prop_name': 'name', 'type': 'text', 'placeholder': 'Name', 'class': 'address.name', 'style': '', 'label': 'Name', 'label_class_li': [] };
template['address']['attention_to'] = { 'obj_type': 'address', 'obj_prop_name': 'attention_to', 'type': 'text', 'placeholder': 'Attention to', 'class': 'address.attention_to', 'style': '', 'label': 'Attention to', 'label_class_li': [] };
template['address']['organization_name'] = { 'obj_type': 'address', 'obj_prop_name': 'organization_name', 'type': 'text', 'placeholder': 'Organization name', 'class': 'address.organization_name', 'style': '', 'label': 'Organization name', 'label_class_li': [] };
template['address']['line_1'] = { 'obj_type': 'address', 'obj_prop_name': 'line_1', 'type': 'text', 'placeholder': 'Line 1', 'class': 'address.line_1', 'style': '', 'label': 'Line 1', 'label_class_li': [] };
template['address']['line_2'] = { 'obj_type': 'address', 'obj_prop_name': 'line_2', 'type': 'text', 'placeholder': 'Line 2', 'class': 'address.line_2', 'style': '', 'label': 'Line 2', 'label_class_li': [] };
template['address']['line_3'] = { 'obj_type': 'address', 'obj_prop_name': 'line_3', 'type': 'text', 'placeholder': 'Line 3', 'class': 'address.line_3', 'style': '', 'label': 'Line 3', 'label_class_li': [] };
template['address']['city'] = { 'obj_type': 'address', 'obj_prop_name': 'city', 'type': 'text', 'placeholder': 'City', 'class': 'address.city', 'style': '', 'label': 'City', 'label_class_li': [] };
template['address']['state_province'] = { 'obj_type': 'address', 'obj_prop_name': 'state_province', 'type': 'text', 'placeholder': 'State/Province', 'class': 'address.state_province', 'style': '', 'label': 'State/Province', 'label_class_li': [] };
template['address']['postal_code'] = { 'obj_type': 'address', 'obj_prop_name': 'postal_code', 'type': 'text', 'placeholder': 'Postal Code', 'class': 'address.postal_code', 'style': '', 'label': 'Postal code', 'label_class_li': [] };
//template['address']['country_alpha_2_code'] = { 'obj_type': 'address', 'obj_prop_name': 'country_alpha_2_code', 'type': 'select', 'placeholder': 'Country alpha 2 code', 'class': 'address.country_alpha_2_code', 'style': '', 'label': 'Country alpha 2 code', 'label_class_li': [], 'select_option_li': { 'CA': 'Canada', 'MX': 'Mexico', 'US': 'United States', 'UK': 'United Kingdom' } };
template['address']['country_alpha_2_code'] = { 'obj_type': 'address', 'obj_prop_name': 'country_alpha_2_code', 'type': 'select', 'placeholder': 'Country alpha 2 code', 'class': 'address.country_alpha_2_code', 'style': '', 'label': 'Country alpha 2 code', 'label_class_li': [], 'select_option_li': { 'CA': 'Canada', 'MX': 'Mexico', 'US': 'United States', 'UK': 'United Kingdom' } };
template['address']['country'] = { 'obj_type': 'address', 'obj_prop_name': 'country', 'type': 'text', 'placeholder': 'Country', 'class': 'address.country', 'style': '', 'label': 'Country', 'label_class_li': [] };
template['address']['timezone'] = { 'obj_type': 'address', 'obj_prop_name': 'timezone', 'type': 'text', 'placeholder': 'Timezone', 'class': 'address.timezone', 'style': '', 'label': 'Timezone', 'label_class_li': [] };
template['address']['latitude'] = { 'obj_type': 'address', 'obj_prop_name': 'latitude', 'type': 'text', 'placeholder': 'Latitude', 'class': 'address.latitude', 'style': '', 'label': 'Latitude', 'label_class_li': [] };
template['address']['longitude'] = { 'obj_type': 'address', 'obj_prop_name': 'longitude', 'type': 'text', 'placeholder': 'Longitude', 'class': 'address.longitude', 'style': '', 'label': 'Longitude', 'label_class_li': [] };
template['address']['map_url'] = { 'obj_type': 'address', 'obj_prop_name': 'map_url', 'type': 'url', 'placeholder': 'Map URL', 'class': 'address.map_url', 'style': '', 'label': 'Map URL', 'label_class_li': [] };
template['address']['congressional_district'] = { 'obj_type': 'address', 'obj_prop_name': 'congressional_district', 'type': 'text', 'placeholder': 'Congressional district', 'class': 'address.congressional_district', 'style': '', 'label': 'Congressional district', 'label_class_li': [] };
template['address']['verified'] = { 'obj_type': 'address', 'obj_prop_name': 'verified', 'type': 'checkbox', 'placeholder': 'Verified', 'class': 'address.verified', 'style': '', 'label': 'Verified', 'label_class_li': [] };
template['address']['created_on'] = { 'obj_type': 'address', 'obj_prop_name': 'created_on', 'type': 'text', 'placeholder': '', 'class': 'address.created_on', 'style': '', 'readonly': 'readonly', 'disabled': 'disabled', 'required': 'required', 'label': 'Created on', 'label_class_li': [] };
template['address']['updated_on'] = { 'obj_type': 'address', 'obj_prop_name': 'updated_on', 'type': 'text', 'placeholder': '', 'class': 'address.updated_on', 'style': '', 'readonly': 'readonly', 'disabled': 'disabled', 'required': 'required', 'label': 'Updated on', 'label_class_li': [] };
// NOTE contact section
template['contact'] = {};
template['contact']['name'] = { 'obj_type': 'contact', 'obj_prop_name': 'name', 'type': 'text', 'placeholder': 'Name', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': 'required', 'label': 'Name', 'label_class_li': [] };
template['contact']['title'] = { 'obj_type': 'contact', 'obj_prop_name': 'title', 'type': 'text', 'placeholder': 'Title', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': 'required', 'label': 'Title', 'label_class_li': [] };
template['contact']['tagline'] = { 'obj_type': 'contact', 'obj_prop_name': 'tagline', 'type': 'checkbox', 'placeholder': 'Tagline', 'class': 'contact.tagline', 'style': '', 'label': 'Tagline', 'label_class_li': [] };
template['contact']['email'] = { 'obj_type': 'contact', 'obj_prop_name': 'email', 'type': 'email', 'placeholder': 'Email address', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': '', 'label': 'Email address', 'label_class_li': [] };
template['contact']['other_site_url'] = { 'obj_type': 'contact', 'obj_prop_name': 'website_url', 'type': 'url', 'placeholder': 'Website URL', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': '', 'label': 'Website URL', 'label_class_li': [] };
template['contact']['website_name'] = { 'obj_type': 'contact', 'obj_prop_name': 'website_name', 'type': 'text', 'placeholder': 'Website name', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': '', 'label': 'Website name', 'label_class_li': [] };
template['contact']['phone_mobile'] = { 'obj_type': 'contact', 'obj_prop_name': 'phone_mobile', 'type': 'tel', 'placeholder': 'Phone mobile', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': '', 'label': 'Phone mobile', 'label_class_li': [] };
template['contact']['phone_home'] = { 'obj_type': 'contact', 'obj_prop_name': 'phone_home', 'type': 'tel', 'placeholder': 'Phone home', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': '', 'label': 'Phone home', 'label_class_li': [] };
template['contact']['phone_office'] = { 'obj_type': 'contact', 'obj_prop_name': 'phone_office', 'type': 'tel', 'placeholder': 'Phone office', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': '', 'label': 'Phone office', 'label_class_li': [] };
template['contact']['phone_land'] = { 'obj_type': 'contact', 'obj_prop_name': 'phone_land', 'type': 'tel', 'placeholder': 'Phone land', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': '', 'label': 'Phone land', 'label_class_li': [] };
template['contact']['phone_fax'] = { 'obj_type': 'contact', 'obj_prop_name': 'phone_fax', 'type': 'tel', 'placeholder': 'Phone fax', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': '', 'label': 'Phone fax', 'label_class_li': [] };
template['contact']['facebook_url'] = { 'obj_type': 'contact', 'obj_prop_name': 'facebook_url', 'type': 'url', 'placeholder': 'Facebook URL', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': '', 'label': 'Facebook URL', 'label_class_li': [] };
template['contact']['instagram_url'] = { 'obj_type': 'contact', 'obj_prop_name': 'instagram_url', 'type': 'url', 'placeholder': 'Instagram URL', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': '', 'label': 'Instagram URL', 'label_class_li': [] };
template['contact']['twitter_url'] = { 'obj_type': 'contact', 'obj_prop_name': 'twitter_url', 'type': 'url', 'placeholder': 'Twitter URL', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': '', 'label': 'Twitter URL', 'label_class_li': [] };
template['contact']['linkedin_url'] = { 'obj_type': 'contact', 'obj_prop_name': 'linkedin_url', 'type': 'url', 'placeholder': 'LinkedIn URL', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': '', 'label': 'LinkedIn URL', 'label_class_li': [] };
template['contact']['other_site_url'] = { 'obj_type': 'contact', 'obj_prop_name': 'other_site_url', 'type': 'url', 'placeholder': 'Other site URL', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': '', 'label': 'Other site URL', 'label_class_li': [] };
template['contact']['others_site_name'] = { 'obj_type': 'contact', 'obj_prop_name': 'others_site_name', 'type': 'text', 'placeholder': 'Other site name', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': '', 'label': 'Other site name', 'label_class_li': [] };
template['contact']['enable'] = { 'obj_type': 'contact', 'obj_prop_name': 'enable', 'type': 'checkbox', 'placeholder': 'Enable', 'class': 'contact.enable', 'style': '', 'label': 'Enable', 'label_class_li': [] };
// NOTE site template section
template['site'] = {};
template['site']['id'] = { 'obj_type': 'site', 'obj_prop_name': 'id', 'type': 'hidden', 'placeholder': '', 'class_li': [], 'style': '', 'readonly': 'readonly', 'disabled': 'disabled', 'required': 'required', 'label': 'ID', 'label_class_li': [] };
template['site']['id_random'] = { 'obj_type': 'site', 'obj_prop_name': 'id_random', 'type': 'hidden', 'placeholder': '', 'class_li': [], 'style': '', 'readonly': 'readonly', 'disabled': 'disabled', 'required': 'required', 'label': 'ID random', 'label_class_li': [] };
//template['site']['fqdn_1'] = { 'obj_type': 'site', 'obj_prop_name': 'fqdn_1', 'type': 'text', 'placeholder': 'FQDN 1', 'class': 'site.fqdn_1', 'style': '', 'label': 'FQDN 1', 'label_class_li': [] };
//template['site']['fqdn_2'] = { 'obj_type': 'site', 'obj_prop_name': 'fqdn_2', 'type': 'text', 'placeholder': 'FQDN 2', 'class': 'site.fqdn_2', 'style': '', 'label': 'FQDN 2', 'label_class_li': [] };
//template['site']['fqdn_3'] = { 'obj_type': 'site', 'obj_prop_name': 'fqdn_3', 'type': 'text', 'placeholder': 'FQDN 2', 'class': 'site.fqdn_3', 'style': '', 'label': 'FQDN 3', 'label_class_li': [] };
template['site']['enable'] = { 'obj_type': 'site', 'obj_prop_name': 'enable', 'type': 'checkbox', 'placeholder': 'Enable', 'class': 'site.enable', 'style': '', 'label': 'Enable', 'label_class_li': [] };
template['site']['name'] = { 'obj_type': 'site', 'obj_prop_name': 'name', 'type': 'text', 'placeholder': 'Name', 'class': 'site.name', 'style': '', 'label': 'Name', 'label_class_li': [] };
template['site']['description'] = { 'obj_type': 'site', 'obj_prop_name': 'description', 'obj_prop_value_pre': true, 'type': 'textarea', 'placeholder': 'Description', 'class': 'site.description', 'style': '', 'label': 'Description', 'label_class_li': [], 'rows': 3, 'cols': 80 };
template['site']['logo_path'] = { 'obj_type': 'site', 'obj_prop_name': 'logo_path', 'type': 'text', 'placeholder': 'Logo path', 'class': 'site.logo_path', 'style': '', 'label': 'Logo path' };
template['site']['banner_image_path'] = { 'obj_type': 'site', 'obj_prop_name': 'banner_image_path', 'type': 'text', 'placeholder': 'Banner image path', 'class': 'site.banner_image_path', 'style': '', 'label': 'Banner image path' };
//template['site']['html_menu_path'] = { 'obj_type': 'site', 'obj_prop_name': 'html_menu_path', 'type': 'text', 'placeholder': 'HTML menu path', 'class': 'site.html_menu_path', 'style': '', 'label': 'HTML menu path' };
template['site']['site_body'] = { 'obj_type': 'site', 'obj_prop_name': 'site_body', 'obj_prop_value_pre': true, 'type': 'textarea', 'placeholder': 'Site body', 'class': 'site.site_body', 'style': '', 'label': 'Site body', 'label_class_li': [], 'rows': 10, 'cols': 80 };
template['site']['site_tagline'] = { 'obj_type': 'site', 'obj_prop_name': 'site_tagline', 'type': 'text', 'placeholder': 'Site tagline', 'class': 'site.site_tagline', 'style': '', 'label': 'Site tagline', 'label_class_li': [] };
template['site']['style_href'] = { 'obj_type': 'site', 'obj_prop_name': 'style_href', 'type': 'text', 'placeholder': 'Style HREF', 'class': 'site.style_href', 'style': '', 'label': 'Style HREF', 'label_class_li': [] };
template['site']['script_src'] = { 'obj_type': 'site', 'obj_prop_name': 'script_src', 'type': 'text', 'placeholder': 'Script SRC', 'class': 'site.script_src', 'style': '', 'label': 'Script SRC', 'label_class_li': [] };
template['site']['google_tracking_id'] = { 'obj_type': 'site', 'obj_prop_name': 'google_tracking_id', 'type': 'text', 'placeholder': 'Google tracking ID', 'class': 'site.google_tracking_id', 'style': '', 'label': 'Google tracking ID', 'label_class_li': [] };
template['site']['created_on'] = { 'obj_type': 'site', 'obj_prop_name': 'created_on', 'type': 'text', 'placeholder': '', 'class': 'site.created_on', 'style': '', 'readonly': 'readonly', 'disabled': 'disabled', 'required': 'required', 'label': 'Created on', 'label_class_li': [] };
template['site']['updated_on'] = { 'obj_type': 'site', 'obj_prop_name': 'updated_on', 'type': 'text', 'placeholder': '', 'class': 'site.updated_on', 'style': '', 'readonly': 'readonly', 'disabled': 'disabled', 'required': 'required', 'label': 'Updated on', 'label_class_li': [] };
// NOTE person section
template['person'] = {};
template['person']['given_name'] = { 'obj_type': 'person', 'obj_prop_name': 'given_name', 'type': 'text', 'placeholder': 'Given name', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': 'required', 'label': 'Given name', 'label_class_li': [] };
template['person']['middle_name'] = { 'obj_type': 'person', 'obj_prop_name': 'middle_name', 'type': 'text', 'placeholder': 'Middle name', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': 'required', 'label': 'Middle name', 'label_class_li': [] };
template['person']['family_name'] = { 'obj_type': 'person', 'obj_prop_name': 'family_name', 'type': 'text', 'placeholder': 'Family name', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': '', 'label': 'Family name', 'label_class_li': [] };
template['person']['title'] = { 'obj_type': 'person', 'obj_prop_name': 'title', 'type': 'text', 'placeholder': 'Title', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': '', 'label': 'Title', 'label_class_li': [] };
template['person']['tagline'] = { 'obj_type': 'person', 'obj_prop_name': 'tagline', 'type': 'text', 'placeholder': 'Tagline', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': '', 'label': 'Tagline', 'label_class_li': [] };
template['person']['organization_name'] = { 'obj_type': 'person', 'obj_prop_name': 'organization_name', 'type': 'text', 'placeholder': 'Organization name', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': '', 'label': 'Organization name', 'label_class_li': [] };
template['person']['notes'] = { 'obj_type': 'person', 'obj_prop_name': 'notes', 'obj_prop_value_pre': true, 'type': 'textarea', 'placeholder': 'Notes', 'class': 'person.notes', 'style': '', 'label': 'Notes', 'label_class_li': [], 'rows': 3, 'cols': 80 };
// NOTE user section
template['user'] = {};
template['user']['email'] = { 'obj_type': 'user', 'obj_prop_name': 'email', 'type': 'email', 'placeholder': 'Email address', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': 'required', 'label': 'Email address', 'label_class_li': [] };
template['user']['name'] = { 'obj_type': 'user', 'obj_prop_name': 'name', 'type': 'text', 'placeholder': 'Name', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': 'required', 'label': 'Name', 'label_class_li': [] };
template['user']['username'] = { 'obj_type': 'user', 'obj_prop_name': 'username', 'type': 'text', 'placeholder': 'Username', 'class_li': [], 'style': '', 'readonly': '', 'disabled': '', 'required': 'required', 'label': 'Username', 'label_class_li': [] };
template['user']['email_verified'] = { 'obj_type': 'user', 'obj_prop_name': 'email_verified', 'type': 'checkbox', 'placeholder': 'Email verified', 'class': 'user.email_verified', 'style': '', 'label': 'Email verified', 'label_class_li': [] };
template['user']['enable'] = { 'obj_type': 'user', 'obj_prop_name': 'enable', 'type': 'checkbox', 'placeholder': 'Enable', 'class': 'user.enable', 'style': '', 'label': 'Enable', 'label_class_li': [] };
export default template;

7
src/index.test.ts Normal file
View File

@@ -0,0 +1,7 @@
import { describe, it, expect } from 'vitest';
describe('sum test', () => {
it('adds 1 + 2 to equal 3', () => {
expect(1 + 2).toBe(3);
});
});

View File

@@ -1,37 +0,0 @@
<script lang="ts">
export let id_random: string = '';
export let obj_type: string = '';
export let obj_prop_name: string = '';
export let name: string = obj_prop_name;
export let id: string = `${name}--${id_random}`; // Same as the value for "for"
export let value: string = '';
export let readonly: string = '';
export let disabled: string = '';
export let required: string = '';
export let type: string = 'text';
//export let class: string = ''; // Probably not going to use
export let class_li: Array<> = [];
export let style: string = '';
export let label: string = '';
export let placeholder: string = label;
export let label_class: string = ''; // Probably not going to use
export let label_class_li: Array<> = [];
</script>
{#if type === 'text' || type === 'email' || type === 'url' || type === 'checkbox' }
<label for={id} class={label_class_li.join(' ')}>{label}</label>
<input {id} {name} class={class_li.join(' ')} {type} {value} {placeholder} {readonly} {disabled} {required} data-id_random={id_random} data-obj_type={obj_type} data-obj_prop_name={obj_prop_name} />
{:else if type === 'textarea'}
<label for={id} class={label_class_li.join(' ')}>{label}</label>
<textarea {id} {name} class={class_li.join(' ')} {value} {placeholder} {readonly} {disabled} {required} data-id_random={id_random} data-obj_type={obj_type} data-obj_prop_name={obj_prop_name}></textarea>
<!-- rows="" cols="" maxlength="" -->
{/if}

319
src/lib/ae_core__person.ts Normal file
View File

@@ -0,0 +1,319 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import { db_core } from "$lib/db_core";
let ae_promises: key_val = {};
// Updated 2024-07-17
export async function handle_load_ae_obj_id__person(
{
api_cfg,
person_id,
try_cache=false,
log_lvl=0
}: {
api_cfg: any,
person_id: string,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** handle_load_ae_obj_id__person() *** person_id=${person_id}`);
let params = {};
ae_promises.load__person_obj = await api.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'person',
obj_id: person_id, // NOTE: This is the FQDN, not normally the ID.
use_alt_table: false, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value
params: params,
log_lvl: log_lvl
})
.then(function (person_obj_get_result) {
if (person_obj_get_result) {
// This is expecting a list
handle_db_save_ae_obj_li__person({obj_type: 'person', obj_li: [person_obj_get_result]});
return person_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
return ae_promises.load__person_obj;
}
// Updated 2024-07-17
export async function handle_load_ae_obj_li__person(
{
api_cfg,
account_id,
params={},
try_cache=true,
log_lvl=0
}: {
api_cfg: any,
account_id: string,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** handle_load_ae_obj_li__person() *** account_id=${account_id}`);
let enabled: string = (params.qry__enabled ?? 'enabled'); // all, disabled, enabled
let hidden: string = (params.qry__hidden ?? 'not_hidden'); // all, hidden, not_hidden
let limit: number = (params.qry__limit ?? 99); // 99
let offset: number = (params.qry__offset ?? 0); // 0
let params_json: key_val = {};
// console.log('params_json:', params_json);
ae_promises.load__person_obj_li = await api.get_ae_obj_li_for_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'person',
for_obj_type: 'account',
for_obj_id: account_id,
use_alt_table: false, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value
enabled: enabled,
hidden: hidden,
order_by_li: {'given_name': 'ASC', 'family_name': 'ASC', 'updated_on': 'DESC', 'created_on': 'DESC'},
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (person_obj_li_get_result) {
if (person_obj_li_get_result) {
handle_db_save_ae_obj_li__person({obj_type: 'person', obj_li: person_obj_li_get_result});
return person_obj_li_get_result;
} else {
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
console.log('ae_promises.load__person_obj_li:', ae_promises.load__person_obj_li);
return ae_promises.load__person_obj_li;
}
// Updated 2024-06-24
export async function handle_create_ae_obj__person(
{
api_cfg,
user_id,
data_kv,
params={},
log_lvl=0
}: {
api_cfg: any,
user_id?: string,
data_kv: key_val,
params?: key_val,
log_lvl?: number
}
) {
console.log(`*** handle_create_ae_obj__person() *** user_id=${user_id}`);
ae_promises.create__person = await api.create_ae_obj_crud({
api_cfg: api_cfg,
obj_type: 'person',
fields: {
user_id_random: user_id,
...data_kv
},
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl
})
.then(function (person_obj_create_result) {
if (person_obj_create_result) {
handle_db_save_ae_obj_li__person(
{
obj_type: 'person', obj_li: [person_obj_create_result]
});
return person_obj_create_result;
} else {
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
});
if (log_lvl) {
console.log('ae_promises.create__person:', ae_promises.create__person);
}
return ae_promises.create__person;
}
// Updated 2024-07-17
export async function handle_update_ae_obj__person(
{
api_cfg,
person_id,
data_kv,
params={},
log_lvl=0
}: {
api_cfg: any,
person_id: string,
data_kv: key_val,
params?: key_val,
log_lvl?: number
}
) {
console.log(`*** handle_update_ae_obj__person() *** person_id=${person_id}`);
ae_promises.update__person_obj = await api.update_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'person',
obj_id: person_id, // NOTE: This is the FQDN, not normally the ID.
fields: data_kv,
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl
})
.then(function (person_obj_update_result) {
if (person_obj_update_result) {
handle_db_save_ae_obj_li__person({obj_type: 'person', obj_li: [person_obj_update_result]});
return person_obj_update_result;
} else {
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
});
if (log_lvl) {
console.log('ae_promises.update__person_obj:', ae_promises.update__person_obj);
}
return ae_promises.update__person_obj;
}
// Updated 2024-06-10
export function handle_db_save_ae_obj_li__person(
{
obj_type,
obj_li,
log_lvl=0
}: {
obj_type: string,
obj_li: any,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** handle_db_save_ae_obj_li__person() ***`);
}
if (obj_li && obj_li.length) {
obj_li.forEach(async function (obj: any) {
if (log_lvl) {
console.log(`ae_obj ${obj_type}:`, obj);
}
try {
const id_random = await db_core.person.put({
id: obj.person_id_random,
// id_random: obj.person_id_random,
person_id: obj.person_id_random,
person_id_random: obj.person_id_random,
external_id: obj.external_id,
external_sys_id: obj.external_sys_id,
code: obj.code,
account_id: obj.account_id_random,
account_id_random: obj.account_id_random,
person_profile_id: obj.person_profile_id_random,
person_profile_id_random: obj.person_profile_id_random, // The new table person_profile will be used soon...
user_id: obj.user_id_random,
user_id_random: obj.user_id_random,
pronouns: obj.pronouns,
informal_name: obj.informal_name,
title_names: obj.title_names,
given_name: obj.given_name,
middle_name: obj.middle_name,
family_name: obj.family_name,
designations: obj.designations,
professional_title: obj.professional_title,
full_name: obj.full_name,
affiliations: obj.affiliations,
primary_email: obj.primary_email,
biography: obj.biography,
agree: obj.agree,
comments: obj.comments,
allow_auth_key: obj.allow_auth_key, // For sign in without password
// auth_key: obj.auth_key,
passcode: obj.passcode,
data_json: obj.data_json,
enable: obj.enable,
hide: obj.hide,
priority: obj.priority,
sort: obj.sort,
group: obj.group,
notes: obj.notes,
created_on: obj.created_on,
updated_on: obj.updated_on,
// From SQL view
username: obj.username,
user_name: obj.user_name,
user_email: obj.user_email,
user_allow_auth_key: obj.user_allow_auth_key, // For sign in without password
user_super: obj.user_super,
user_manager: obj.user_manager,
user_administrator: obj.user_administrator,
user_public: obj.user_public,
});
// console.log(`Put obj with ID: ${obj.person_id_random} or ${id_random}`);
} catch (error) {
let status = `Failed to put ${obj.person_id_random}: ${error}`;
console.log(status);
}
// const id_random = await db_core.person.put(obj);
// console.log(`Put obj with ID: ${obj.person_id_random}`);
});
return true;
}
}

115
src/lib/ae_core__qr_code.ts Normal file
View File

@@ -0,0 +1,115 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import { db_core } from "$lib/db_core";
let ae_promises: key_val = {};
// Updated 2024-07-18
export async function generate_qr_code(
{
api_cfg,
account_id,
qr_type, // mecard, obj, str, vcard
qr_id, // This is essentially the filename it can be found at /qr/{account_id}/{qr_id}
qr_data, // vcard fields:
obj_type,
obj_id,
str, // For encoding a string (like a URL) into a QR code.
return_blob=true, // blob or url?
try_cache=false,
log_lvl=0
}: {
api_cfg: any,
account_id: string,
qr_type: string,
qr_id: string,
qr_data?: any,
obj_type?: string,
obj_id?: string,
str?: string,
return_blob?: boolean,
try_cache?: boolean,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** generate_qr_code() *** qr_id=${qr_id}`);
}
let endpoint = `/qr/${account_id}/${qr_id}`;
if (log_lvl) {
console.log('Endpoint', endpoint);
}
let params: key_val = {
'regen': true, // Regenerate the file even if nothing has changed.
'return_file': return_blob,
'qr_type': qr_type, // mecard, obj, vcard
'qr_send': return_blob
};
if (qr_type == 'vcard') {
if (qr_data.informal_name) {
params['n'] = `${qr_data.family_name};${qr_data.given_name};${qr_data.informal_name}`;
} else {
params['n'] = `${qr_data.family_name};${qr_data.given_name}`;
}
params['fn'] = qr_data.full_name_override;
if (qr_data.affiliations) { params['org'] = qr_data.affiliations; }
// url
params['email'] = qr_data.email;
if (qr_data.phone) { params['tel'] = qr_data.phone; }
params['adr'] = qr_data.location_override;
if (qr_data.address_line_1) { params['adr_str'] = qr_data.address_line_1; }
params['adr_loc'] = qr_data.city;
params['adr_reg'] = qr_data.state_province;
params['adr_postal'] = qr_data.postal_code;
params['adr_country'] = qr_data.country;
} else if (qr_type == 'obj') {
params['obj_type'] = obj_type;
params['obj_id'] = obj_id;
} else if (qr_type == 'str') {
params['str'] = str;
}
if (log_lvl) {
console.log('Params', params);
}
// let filename = `qr_${$ae_loc.account_id}_${qr_id}_${qr_type}.png`;
let filename = null;
ae_promises.generate_qr_code = await api.get_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
return_blob: return_blob,
filename: filename,
auto_download: false,
log_lvl: log_lvl
});
console.log('QR code generated done!?');
if (return_blob) {
let img_blob = new Blob([ae_promises.generate_qr_code.data]);
let img_obj_url = URL.createObjectURL(img_blob);
// console.log(img_obj_url);
// return img_blob;
return img_obj_url;
}
// let img_blob = new Blob([ae_promises.generate_qr_code.data]);
// console.log(img_blob);
// let img_obj_url = URL.createObjectURL(img_blob);
// console.log(img_obj_url);
// let qr_img_src = img_obj_url;
return ae_promises.generate_qr_code;
}

View File

@@ -0,0 +1,413 @@
import { browser } from '$app/environment';
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import {
handle_load_ae_obj_id__person,
handle_load_ae_obj_li__person,
handle_create_ae_obj__person,
handle_update_ae_obj__person,
// handle_db_save_ae_obj_li__person
} from "$lib/ae_core__person";
import {
generate_qr_code,
} from "$lib/ae_core__qr_code";
let ae_promises: key_val = {}; // Promise<any>;
// Updated 2024-08-12
async function check_hosted_file_obj_w_hash(
{
api_cfg,
hosted_file_hash,
check_for_local=true,
params={},
return_meta=false,
log_lvl=0
} : {
api_cfg: any,
hosted_file_hash: string,
check_for_local?: boolean,
params?: key_val,
return_meta?: boolean,
log_lvl?: number
}
) {
console.log('*** stores_event_api.js: check_hosted_file_obj_w_hash() ***');
const endpoint = `/hosted_file/hash/${hosted_file_hash}`;
if (check_for_local) {
params['check_for_local'] = true;
}
let check_hosted_file_obj_w_hash_get_promise = await api.get_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
return_meta: return_meta,
log_lvl: log_lvl
});
return check_hosted_file_obj_w_hash_get_promise;
}
// Updated 2024-03-29
async function handle_load_ae_obj_id__site_domain(
{
api_cfg,
fqdn,
try_cache=false,
timeout=7000,
log_lvl=0
}: {
api_cfg: any,
fqdn: string,
try_cache: boolean,
timeout: number,
log_lvl: number
}
) {
console.log(`*** handle_load_ae_obj_id__site_domain() *** fqdn=${fqdn}`);
let no_account_id = false;
if (!api_cfg.account_id) {
no_account_id = true;
// api_cfg.headers['x_account_id'] = 'nothing here';
}
no_account_id = true;
let params = {};
// ae_loc.hub.site_domain_id_qry_status = 'loading';
ae_promises.load__site_domain_obj = api.get_ae_obj_id_crud({
api_cfg: api_cfg,
no_account_id: no_account_id,
obj_type: 'site_domain',
obj_id: fqdn, // NOTE: This is the FQDN, not normally the ID.
use_alt_table: true, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: true, // NOTE: This will use the base_name_alt value instead of the base_name value in the API config.
params: params,
timeout: timeout,
log_lvl: log_lvl
})
.then(function (site_domain_obj_get_result) {
if (site_domain_obj_get_result) {
// slct.site_domain_obj = site_domain_obj_get_result;
// console.log(`site_domain object:`, get(slct).site_domain_obj);
// ae_loc.account_id = $slct.site_domain_obj.account_id_random;
// ae_loc.site_id = $slct.site_domain_obj.site_id_random;
// ae_loc.site_domain_id = $slct.site_domain_obj.site_domain_id_random;
return site_domain_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
return ae_promises.load__site_domain_obj;
}
// Updated 2024-03-29
async function handle_load_ae_obj_code__data_store(
{
api_cfg,
code,
data_type='text',
for_type=null,
for_id=null,
try_cache=true,
save_idb=false,
timeout=9000,
log_lvl=0
}: {
api_cfg: any,
code: string,
data_type: string,
for_type: string|null,
for_id: string|null,
try_cache: boolean,
save_idb: boolean,
timeout: number,
log_lvl: number
}
) {
if (log_lvl) {
console.log(`*** handle_get_data_store_obj_w_code() *** code=${code}`);
}
if (!code) {
console.log(`*ae_func* No code provided!`);
return false;
}
if (!api_cfg.account_id) {
console.log(`*ae_func* No account_id found in API config!`);
return false;
}
ae_promises.load__data_store_obj = api.get_data_store_obj_w_code({
api_cfg: api_cfg,
data_store_code: code,
data_type: data_type,
timeout: timeout,
log_lvl: log_lvl
})
.then(function (get_ds_result) {
let return_this = null;
if (get_ds_result) {
if (log_lvl) {
console.log(`*ae_func* Got a result for code ${code}`);
}
if (!get_ds_result.data_store_id_random) {
console.log('*ae_func* Something went wrong? No data store ID found.');
return false;
}
// let ae_ds_tmp: key_val = {};
let ds_code_obj =
{
id: null,
account_id: null,
code: code,
name: null,
type: data_type,
for_type: null, // for_type
for_id: null, // for_id
access_read: null, // 'super', 'administrator', 'trusted', 'anonymous'
access_write: null, // 'super', 'administrator', 'trusted', 'anonymous'
access_delete: null, // 'super', 'administrator', 'trusted', 'anonymous'
html: null,
json: null,
md: null,
text: null,
updated_on: null,
chk_account_id: api_cfg.account_id,
loaded_on: new Date().toISOString(),
};
let val_json: key_val;
let val_html: key_val;
let val_md: key_val;
let val_sql: key_val;
let val_text: string;
// Set the loaded_on datetime to the current time for reference later. This will be used to determine if the data store is stale.
// ds_code_obj.loaded_on = new Date().toISOString();
// Set the chk_account_id as a backup check to make sure the data store belongs to the account for the current site. This should not be needed, but here we are...
// ds_code_obj.chk_account_id = api_cfg.account_id;
ds_code_obj.id = get_ds_result.data_store_id_random;
ds_code_obj.account_id = get_ds_result.account_id_random;
ds_code_obj.code = get_ds_result.code; // This will overwrite whatever was passed in.
ds_code_obj.name = get_ds_result.name;
ds_code_obj.type = get_ds_result.type; // This will overwrite whatever was passed in.
if (data_type == 'html') {
ds_code_obj.html = get_ds_result.text;
val_html = get_ds_result.text;
return_this = get_ds_result.html;
} else if (data_type == 'json') {
ds_code_obj.json = get_ds_result.json;
val_json = get_ds_result.json;
return_this = get_ds_result.json;
} else if (data_type == 'md') {
ds_code_obj.text = get_ds_result.text;
val_md = get_ds_result.text;
return_this = get_ds_result.text;
} else if (data_type == 'sql') {
ds_code_obj.text = get_ds_result.text;
val_sql = get_ds_result.text;
return_this = get_ds_result.text;
} else {
ds_code_obj.text = get_ds_result.text;
val_text = get_ds_result.text;
return_this = get_ds_result.text;
}
// if (data_type == 'text') {
// // console.log(get_ds_result.text);
// return_this = get_ds_result.text;
// } else if (data_type == 'json') {
// // console.log(get_ds_result.json);
// return_this = get_ds_result.json;
// }
if (save_idb) {
if (browser) {
let key_prefix = 'ae_ds__';
if (log_lvl) {
console.log(`*ae_func* localStorage key: ${code}, value:`, get_ds_result);
}
localStorage.setItem(`${key_prefix}${code}`, JSON.stringify(get_ds_result));
} else {
if (log_lvl) {
console.log('*ae_func* No browser! Can not use localStorage to save data store object.');
}
}
}
} else {
console.log('*ae_func* No results returned.');
return_this = null;
}
return return_this;
})
.catch(function (error) {
console.log('*ae_func* No results returned or failed.', error);
});
return ae_promises.load__data_store_obj;
}
// Updated 2024-03-27
async function handle_update_ae_obj_id_crud(
{
api_cfg,
object_type,
object_id,
field_name,
new_field_value,
params={},
try_cache=false,
log_lvl=0
}: {
api_cfg: any,
object_type: string,
object_id: string,
field_name: string,
new_field_value: any,
params: any|key_val,
try_cache: boolean,
log_lvl: number
}) {
let patch_result: any = null;
ae_promises.api_update__ae_obj = api.update_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: object_type,
obj_id: object_id,
field_name: field_name,
field_value: new_field_value,
// fields: data,
key: api_cfg.api_crud_super_key,
// jwt: null,
// params: params,
// data: patch_data,
log_lvl: log_lvl
})
.then(function (results) {
console.log('PATCH Promise', results);
if (results) {
console.log(`Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}`);
patch_result = 'PATCH complete';
} else {
console.log(`Not Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}; Account ID: ${api_cfg.account_id}`);
patch_result = 'PATCH failed';
return false;
}
return true;
})
.catch(function (error) {
console.log('Something went wrong patching the record.');
console.log(error);
return false;
})
.finally(function () {
console.log('PATCH Promise finally');
});
return ae_promises.api_update__ae_obj;
}
async function handle_download_export__obj_type(
{
api_cfg,
get_obj_type, // The type of object to return: event_badge, event_presenter, sponsorship, etc.
for_obj_type, // Usually for an account, event, event_exhibit, or sponsorship_cfg
for_obj_id, // The ID of the object
file_type='CSV', // 'CSV' or 'Excel'
return_file=true,
filename='no_filename.csv',
auto_download=false,
limit=5000,
params={}, // key value object is expected
log_lvl=0
}: {
api_cfg: any,
get_obj_type: string,
for_obj_type: string,
for_obj_id: string,
file_type?: string,
return_file?: boolean,
filename?: string,
auto_download?: boolean,
limit?: number,
params?: key_val,
log_lvl?: number
}
) {
console.log('*** ae_core_functions.js: handle_download_export__obj_type() ***');
let task_id = for_obj_id;
const endpoint = `/v2/crud/${get_obj_type}/list`;
params['for_obj_type'] = for_obj_type;
params['for_obj_id'] = for_obj_id;
if (file_type == 'CSV' || file_type == 'Excel') {
params['file_type'] = file_type;
}
params['return_file'] = true;
params['mdl_alt'] = 'out';
// let clean_filename = filename.replace(/[^a-z0-9]/gi, '_');
// let clean_filename = filename.replace(/[^a-z0-9\[\]-]/gi, '_');
let clean_filename = filename.replace(/[^a-zA-Z0-9\[\]-_.]/gi, '_');
// let clean_filename = filename.replace(/[^a-zA-Z0-9\[\]-\._ ]/gi, '_');
if (limit >= 0) {
params['limit'] = limit;
}
ae_promises.download__sponsorship_export_file = await api.get_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
return_blob: return_file,
filename: clean_filename,
auto_download: auto_download,
task_id: task_id,
log_lvl: log_lvl
});
console.log('ae_promises.download__sponsorship_export_file:', ae_promises.download__sponsorship_export_file);
return ae_promises.download__sponsorship_export_file;
}
let export_obj = {
check_hosted_file_obj_w_hash: check_hosted_file_obj_w_hash,
handle_load_ae_obj_id__site_domain: handle_load_ae_obj_id__site_domain,
handle_load_ae_obj_code__data_store: handle_load_ae_obj_code__data_store,
handle_load_ae_obj_id__person: handle_load_ae_obj_id__person,
handle_load_ae_obj_li__person: handle_load_ae_obj_li__person,
handle_create_ae_obj__person: handle_create_ae_obj__person,
handle_update_ae_obj__person: handle_update_ae_obj__person,
handle_update_ae_obj_id_crud: handle_update_ae_obj_id_crud,
handle_download_export__obj_type: handle_download_export__obj_type,
generate_qr_code: generate_qr_code
};
export let core_func = export_obj;

203
src/lib/ae_events__event.ts Normal file
View File

@@ -0,0 +1,203 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import { db_events } from "$lib/db_events";
let ae_promises: key_val = {};
// Updated 2024-07-02
export async function handle_load_ae_obj_id__event(
{
api_cfg,
event_id,
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
event_id: string,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** handle_load_ae_obj_id__event() *** event_id=${event_id}`);
let params = {};
// $events_sess.badges.status_load__event_obj = 'loading';
ae_promises.load__event_obj = await api.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event',
obj_id: event_id, // NOTE: This is the FQDN, not normally the ID.
use_alt_table: true, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value in the API config.
params: params,
log_lvl: log_lvl
})
.then(function (event_obj_get_result) {
if (event_obj_get_result) {
if (try_cache) {
// This is expecting a list
handle_db_save_ae_obj_li__event({
obj_type: 'event',
obj_li: [event_obj_get_result]
});
}
return event_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
return ae_promises.load__event_obj;
}
// Updated 2024-05-24
export async function handle_load_ae_obj_li__event(
{
api_cfg,
account_id,
params={},
try_cache=true,
log_lvl=0
}: {
api_cfg: any,
account_id: string,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** handle_load_ae_obj_li__event() *** account_id=${account_id}`);
let enabled: string = (params.qry__enabled ?? 'enabled'); // all, disabled, enabled
let hidden: string = (params.qry__hidden ?? 'not_hidden'); // all, hidden, not_hidden
let limit: number = (params.qry__limit ?? 99); // 99
let offset: number = (params.qry__offset ?? 0); // 0
let params_json: key_val = {};
// console.log('params_json:', params_json);
ae_promises.load__event_obj_li = await api.get_ae_obj_li_for_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event',
for_obj_type: 'account',
for_obj_id: account_id,
use_alt_table: true, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value
enabled: enabled,
hidden: hidden,
order_by_li: {'start_datetime': 'DESC', 'name': 'ASC', 'updated_on': 'DESC', 'created_on': 'DESC'},
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (event_obj_li_get_result) {
if (event_obj_li_get_result) {
if (try_cache) {
handle_db_save_ae_obj_li__event({obj_type: 'event', obj_li: event_obj_li_get_result});
}
return event_obj_li_get_result;
} else {
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.load__event_obj_li:', ae_promises.load__event_obj_li);
}
return ae_promises.load__event_obj_li;
}
// This function will loop through the event_obj_li and save each one to the DB.
export function handle_db_save_ae_obj_li__event(
{
obj_type,
obj_li,
log_lvl = 0
}: {
obj_type: string,
obj_li: any,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** handle_db_save_ae_obj_li__event() ***`);
}
if (obj_li && obj_li.length) {
obj_li.forEach(async function (obj: any) {
if (log_lvl) {
console.log(`ae_obj ${obj_type}:`, obj);
}
try {
const id_random = await db_events.events.put({
id: obj.event_id_random,
// id_random: obj.event_id_random,
event_id: obj.event_id_random,
event_id_random: obj.event_id_random,
code: obj.event_code,
account_id: obj.account_id_random,
account_id_random: obj.account_id_random,
conference: obj.conference,
type: obj.type,
name: obj.name,
summary: obj.summary,
description: obj.description,
start_datetime: obj.start_datetime,
end_datetime: obj.end_datetime,
timezone: obj.timezone,
location_address_json: obj.location_address_json,
mod_abstracts_json: obj.mod_abstracts_json,
mod_badges_json: obj.mod_badges_json,
mod_exhibits_json: obj.mod_exhibits_json,
mod_pres_mgmt_json: obj.mod_pres_mgmt_json,
cfg_json: obj.cfg_json,
enable: obj.enable,
hide: obj.hide,
priority: obj.priority,
sort: obj.sort,
group: obj.group,
notes: obj.notes,
created_on: obj.created_on,
updated_on: obj.updated_on,
// From SQL view
file_count: obj.file_count,
file_count_all: obj.file_count_all,
internal_use_count: obj.internal_use_count,
event_file_id_li_json: obj.event_file_id_li_json,
});
// console.log(`Put obj with ID: ${obj.event_id_random} or ${id_random}`);
} catch (error) {
let status = `Failed to put ${obj.event_id_random}: ${error}`;
console.log(status);
}
// const id_random = await db_events.events.put(obj);
// console.log(`Put obj with ID: ${obj.event_id_random}`);
});
return true;
}
}

View File

@@ -0,0 +1,353 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import { db_events } from "$lib/db_events";
let ae_promises: key_val = {};
// Updated 2024-03
export async function handle_load_ae_obj_id__badge(
{
api_cfg,
badge_id,
try_cache=false,
log_lvl=0
}: {
api_cfg: any,
badge_id: string,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** handle_load_ae_obj_id__badge() *** badge_id=${badge_id}`);
let params = {};
// $events_sess.badges.status_load__badge_obj = 'loading';
ae_promises.load__badge_obj = await api.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_badge',
obj_id: badge_id, // NOTE: This is the FQDN, not normally the ID.
use_alt_table: false, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value in the API config.
params: params,
log_lvl: 0
})
.then(function (badge_obj_get_result) {
if (badge_obj_get_result) {
// This is expecting a list
handle_db_save_ae_obj_li__badge({obj_type: 'event_badge', obj_li: [badge_obj_get_result]});
return badge_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
return ae_promises.load__badge_obj;
}
// Updated 2024-03-06
export async function handle_load_ae_obj_li__badge(
{
api_cfg,
event_id,
params={},
try_cache=true,
log_lvl=0
}: {
api_cfg: any,
event_id: any,
params: any,
try_cache?: boolean,
log_lvl: number
}) {
console.log(`*** handle_load_ae_obj_li__badge() *** event_id=${event_id}`);
let fulltext_search_qry_str = ''; // $events_sess.badges.fulltext_search_qry_str;
let enabled: string = (params.qry__enabled ?? 'enabled'); // all, disabled, enabled
let hidden: string = (params.qry__hidden ?? 'not_hidden'); // all, hidden, not_hidden
let limit: number = (params.qry__limit ?? 99); // 99
let offset: number = (params.qry__offset ?? 0); // 0
let params_json: key_val = {};
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2) {
params_json['ft_qry'] = {
'default_qry_str': fulltext_search_qry_str,
// 'location_address_json_ext': fulltext_search_qry_str, // JSON extracted text DB field
// 'contact_li_json_ext': fulltext_search_qry_str, // JSON extracted text DB field
};
}
// console.log('params_json:', params_json);
// console.log(params_json);
// $events_sess.badges.status_qry__search = 'loading';
ae_promises.load__event_badge_obj_li = await api.get_ae_obj_li_for_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_badge',
for_obj_type: 'event',
for_obj_id: event_id,
use_alt_table: false, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value in the API config.
enabled: enabled,
hidden: hidden,
order_by_li: {'priority': 'DESC', 'sort': 'DESC', 'updated_on': 'DESC', 'created_on': 'DESC'},
// order_by_li: {'priority': 'DESC', 'sort': 'DESC', 'created_on': 'DESC', 'updated_on': 'DESC'},
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (badge_obj_li_get_result) {
// console.log('Badge list:', badge_obj_li_get_result);
if (badge_obj_li_get_result) {
// $slct.badge_obj_li = badge_obj_li_get_result;
handle_db_save_ae_obj_li__badge({obj_type: 'event_badge', obj_li: badge_obj_li_get_result});
return badge_obj_li_get_result;
} else {
// $slct.badge_obj_li = [];
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
// $events_sess.badges.status_qry__search = 'done';
// console.log('Badge list:', badge_obj_li_get_result);
// return badge_obj_li_get_result;
});
if (log_lvl) {
console.log('ae_promises.load__event_badge_obj_li:', ae_promises.load__event_badge_obj_li);
}
return ae_promises.load__event_badge_obj_li;
}
export async function handle_search__event_badge(
{
api_cfg,
event_id,
type_code = null,
fulltext_search_qry_str,
like_search_qry_str = null,
external_event_id,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
event_id: any,
type_code: any,
fulltext_search_qry_str: any,
like_search_qry_str: any,
external_event_id: any,
params: any,
try_cache: boolean,
log_lvl: number
}
) {
console.log(`*** handle_search__event_badge() *** event_id=${event_id}`);
let enabled: string = (params.qry__enabled ?? 'enabled'); // all, disabled, enabled
let hidden: string = (params.qry__hidden ?? 'not_hidden'); // all, hidden, not_hidden
let limit: number = (params.qry__limit ?? 25); // 99
let offset: number = (params.qry__offset ?? 0); // 0
let params_json: key_val = {};
if (!fulltext_search_qry_str && !like_search_qry_str) {
console.log('No search string provided!!!');
return false; // Returning false instead of [] because no search was performed.
}
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2) {
params_json['ft_qry'] = {
'default_qry_str': fulltext_search_qry_str,
// 'location_address_json_ext': fulltext_search_qry_str, // JSON extracted text DB field
// 'contact_li_json_ext': fulltext_search_qry_str, // JSON extracted text DB field
};
}
if (like_search_qry_str && like_search_qry_str.length > 2) {
// Old Python version that needs to be in JS
// # Strip (left right) whitespace then commas then semicolons
// query_str = query_str.strip().strip(',').strip(';')
// # Replace commas, semicolons, and then spaces with %
// query_str_like = query_str.replace(',', ' ').replace(';', ' ').replace(' ', '%').replace(' ', '%')
// # data['query_str'] = f'%{query_str}%'
// log.debug(query_str_like)
// data['query_str'] = f'%{query_str_like}%'
// let like_search_qry_str_new = like_search_qry_str.trim().replace(',', ' ').replace(';', ' ').replace(' ', '%').replace(' ', '%');
// like_search_qry_str_new = `%${like_search_qry_str_new}%`;
// console.log('like_search_qry_str_new:', like_search_qry_str_new);
params_json['and_like'] = {
'default_qry_str': like_search_qry_str,
};
}
params_json['and_qry'] = {};
if (external_event_id) {
params_json['and_qry']['external_event_id'] = external_event_id;
}
if (type_code) { // This is the event_badge.badge_type_code. There is also a member_type_code and registration_type_code that could be referenced in the future.
params_json['and_qry']['badge_type_code'] = type_code;
}
let order_by_li = {'print_count': 'ASC', 'priority': 'DESC', 'sort': 'DESC', 'given_name': 'ASC', 'family_name': 'ASC', 'updated_on': 'DESC', 'created_on': 'DESC'};
// $events_sess.badges.status_qry__search = 'loading';
ae_promises.search__event_badge = await api.get_ae_obj_li_for_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_badge',
for_obj_type: 'event',
for_obj_id: event_id,
use_alt_table: false, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value in the API config.
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
// order_by_li: {'priority': 'DESC', 'sort': 'DESC', 'created_on': 'DESC', 'updated_on': 'DESC'},
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (badge_obj_li_get_result) {
// console.log('Badge list:', badge_obj_li_get_result);
if (badge_obj_li_get_result) {
// $slct.badge_obj_li = badge_obj_li_get_result;
handle_db_save_ae_obj_li__badge({obj_type: 'event_badge', obj_li: badge_obj_li_get_result});
return badge_obj_li_get_result;
} else {
// $slct.badge_obj_li = [];
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
// $events_sess.badges.status_qry__search = 'done';
// console.log('Badge list:', badge_obj_li_get_result);
// return badge_obj_li_get_result;
});
if (log_lvl) {
console.log('ae_promises.search__event_badge:', ae_promises.search__event_badge);
}
return ae_promises.search__event_badge;
}
// This function will loop through the badge_obj_li and save each one to the DB.
export function handle_db_save_ae_obj_li__badge(
{
obj_type,
obj_li,
log_lvl = 0
}: {
obj_type: string,
obj_li: any,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** handle_db_save_ae_obj_li__badge() ***`);
}
if (obj_li && obj_li.length) {
obj_li.forEach(async function (obj: any) {
if (log_lvl) {
console.log(`ae_obj ${obj_type}:`, obj);
}
try {
const id_random = await db_events.badges.put({
id_random: obj.event_badge_id_random,
event_badge_id_random: obj.event_badge_id_random,
event_id_random: obj.event_id_random,
pronouns: obj.pronouns,
informal_name: obj.informal_name,
title_names: obj.title_names,
given_name: obj.given_name,
middle_name: obj.middle_name,
family_name: obj.family_name,
designations: obj.designations,
professional_title: obj.professional_title,
professional_title_override: obj.professional_title_override,
full_name: obj.full_name,
full_name_override: obj.full_name_override,
affiliations: obj.affiliations,
affiliations_override: obj.affiliations_override,
email: obj.email,
email_override: obj.email_override,
address_line_1: obj.address_line_1,
address_line_2: obj.address_line_2,
address_line_3: obj.address_line_3,
city: obj.city,
country_subdivision_code: obj.country_subdivision_code,
state_province: obj.state_province,
state_province_abb: obj.state_province_abb,
postal_code: obj.postal_code,
country_alpha_2_code: obj.country_alpha_2_code,
country: obj.country,
full_address: obj.full_address,
location: obj.location,
location_override: obj.location_override,
query_str: obj.query_str,
badge_type: obj.badge_type,
badge_type_code: obj.badge_type_code,
badge_type_override: obj.badge_type_override,
badge_type_code_override: obj.badge_type_code_override,
external_event_id: obj.external_event_id,
external_id: obj.external_id,
external_person_id: obj.external_person_id,
enable: obj.enable,
hide: obj.hide,
priority: obj.priority,
sort: obj.sort,
group: obj.group,
notes: obj.notes,
created_on: obj.created_on,
updated_on: obj.updated_on,
});
// console.log(`Put obj with ID: ${obj.event_badge_id_random} or ${id_random}`);
} catch (error) {
let status = `Failed to put ${obj.event_badge_id_random}: ${error}`;
console.log(status);
}
// const id_random = await db_events.badges.put(obj);
// console.log(`Put obj with ID: ${obj.event_badge_id_random}`);
});
return true;
}
}

View File

@@ -0,0 +1,577 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import { db_events } from "$lib/db_events";
let ae_promises: key_val = {};
// Updated 2024-06-14
export async function handle_load_ae_obj_id__event_file(
{
api_cfg,
event_file_id,
try_cache=false,
log_lvl=0
}: {
api_cfg: any,
event_file_id: string,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** handle_load_ae_obj_id__event_file() *** event_file_id=${event_file_id}`);
let params = {};
ae_promises.load__event_file_obj = await api.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_file',
obj_id: event_file_id, // NOTE: This is the FQDN, not normally the ID.
use_alt_table: false, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value
params: params,
log_lvl: log_lvl
})
.then(function (event_file_obj_get_result) {
if (event_file_obj_get_result) {
// This is expecting a list
db_save_ae_obj_li__event_file({obj_type: 'event_file', obj_li: [event_file_obj_get_result]});
return event_file_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
return ae_promises.load__event_file_obj;
}
// Updated 2024-07-03
export async function handle_load_ae_obj_li__event_file(
{
api_cfg,
for_obj_type,
for_obj_id,
params={},
try_cache=true,
log_lvl=0
}: {
api_cfg: any,
for_obj_type: string,
for_obj_id: string,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** handle_load_ae_obj_li__event_file() *** for_obj_type=${for_obj_type} for_obj_id=${for_obj_id}`);
// Check if for_obj_type is in the list of valid Aether object types:
let valid_for_obj_types = ['event', 'event_session', 'event_presentation', 'event_presenter', 'event_location'];
if (!valid_for_obj_types.includes(for_obj_type)) {
console.log(`Invalid for_obj_type: ${for_obj_type}`);
return [];
}
let enabled: string = (params.qry__enabled ?? 'enabled'); // all, disabled, enabled
let hidden: string = (params.qry__hidden ?? 'all'); // all, hidden, not_hidden
let limit: number = (params.qry__limit ?? 99); // 99
let offset: number = (params.qry__offset ?? 0); // 0
let params_json: key_val = {};
// console.log('params_json:', params_json);
ae_promises.load__event_file_obj_li = await api.get_ae_obj_li_for_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_file',
for_obj_type: for_obj_type,
for_obj_id: for_obj_id,
use_alt_table: true, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value
enabled: enabled,
hidden: hidden,
order_by_li: {'priority': 'DESC', 'sort': 'DESC', 'updated_on': 'DESC', 'created_on': 'DESC'},
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (event_file_obj_li_get_result) {
if (event_file_obj_li_get_result) {
if (try_cache) {
db_save_ae_obj_li__event_file({obj_type: 'event_file', obj_li: event_file_obj_li_get_result});
}
return event_file_obj_li_get_result;
} else {
console.log('No results returned.');
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.load__event_file_obj_li:', ae_promises.load__event_file_obj_li);
}
return ae_promises.load__event_file_obj_li;
}
// Updated 2024-06-17
export async function handle_delete_ae_obj_id__event_file(
{
api_cfg,
event_file_id,
params={},
log_lvl=0
}: {
api_cfg: any,
event_file_id: string,
params?: key_val,
log_lvl?: number
}
) {
console.log(`*** handle_delete_ae_obj_id__event_file() *** event_file_id=${event_file_id}`);
const endpoint = `/event/file/${event_file_id}/v2`;
params['delete_hosted_file'] = true; // This does not actually delete the hosted file from the server.
params['rm_orphan'] = true; // This is what actually allows the hosted file to be deleted from the server.
ae_promises.delete__event_file_obj = await api.delete_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
// return_meta: return_meta,
log_lvl: log_lvl
});
db_events.files.delete(event_file_id);
return ae_promises.delete__event_file_obj;
}
// Updated 2024-06-14
export async function create_event_file_obj_from_hosted_file_async(
{
api_cfg,
hosted_file_id,
params={},
data={},
return_obj=false,
inc_hosted_file=false,
return_meta=false,
log_lvl=0
}: {
api_cfg: any,
hosted_file_id: string,
params?: key_val,
data?: key_val,
return_obj?: boolean,
inc_hosted_file?: boolean,
return_meta?: boolean,
log_lvl?: number
}
) {
console.log('*** ae_events_functions.js: create_event_file_obj_from_hosted_file() ***');
let endpoint = `/event/file/from_hosted_file/${hosted_file_id}`;
if (return_obj) {
params['return_obj'] = true;
}
if (inc_hosted_file) {
params['inc_hosted_file'] = true;
}
let event_file_obj_post_promise = await api.post_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
data: data,
// return_obj: return_obj,
return_meta: return_meta,
log_lvl: log_lvl
})
.then(function (result) {
console.log('POST DONE create_event_file_obj_from_hosted_file');
console.log(result);
return result;
})
.catch(function (error) {
console.log(error);
return false; // Returning false since something may have gone wrong. Also more in line with what the API returns.
// return error;
});
// console.log(event_file_obj_post_promise);
if (return_obj) {
return event_file_obj_post_promise;
} else {
return event_file_obj_post_promise.event_file_id_random;
}
}
// Updated 2024-06-13
export async function handle_update_ae_obj__event_file(
{
api_cfg,
event_file_id,
data_kv,
params={},
log_lvl=0
}: {
api_cfg: any,
event_file_id: string,
data_kv: key_val,
params?: key_val,
log_lvl?: number
}
) {
console.log(`*** handle_update_ae_obj__event_file() *** event_file_id=${event_file_id}`);
ae_promises.update__event_file_obj = await api.update_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_file',
obj_id: event_file_id, // NOTE: This is the FQDN, not normally the ID.
fields: data_kv,
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl
})
.then(function (event_file_obj_update_result) {
if (event_file_obj_update_result) {
// db_save_ae_obj_li__event_file({obj_type: 'event_file', obj_li: [event_file_obj_update_result]});
// Very important: The results returned from the API does not include fields from the DB views. It is the actual table fields only.
db_update_ae_obj_id__event_file({obj_type: 'event_file', obj_id: event_file_id, data_kv: event_file_obj_update_result});
return event_file_obj_update_result;
} else {
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
});
if (log_lvl) {
console.log('ae_promises.update__event_file_obj:', ae_promises.update__event_file_obj);
}
return ae_promises.update__event_file_obj;
}
// Updated 2024-07-12
export async function search__event_file(
{
api_cfg,
event_id,
created_on = null,
fulltext_search_qry_str,
ft_file_search_qry_str,
like_search_qry_str = null,
like_presentation_search_qry_str = null,
like_file_search_qry_str = null,
order_by_li = {'priority': 'DESC', 'sort': 'DESC', 'filename': 'ASC', 'extension': 'ASC', 'hosted_file_size': 'ASC', 'updated_on': 'DESC', 'created_on': 'DESC'},
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
event_id: any,
created_on?: null|string,
fulltext_search_qry_str?: null|string,
ft_file_search_qry_str?: null|string,
like_search_qry_str?: null|string,
like_presentation_search_qry_str?: null|string,
like_file_search_qry_str?: null|string,
order_by_li?: key_val,
params?: any,
try_cache?: boolean,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** search__event_file() *** event_id=${event_id}`);
}
let enabled: string = (params.qry__enabled ?? 'enabled'); // all, disabled, enabled
let hidden: string = (params.qry__hidden ?? 'not_hidden'); // all, hidden, not_hidden
let limit: number = (params.qry__limit ?? 25); // 99
let offset: number = (params.qry__offset ?? 0); // 0
let params_json: key_val = {};
// if (!fulltext_search_qry_str && !like_search_qry_str) {
// console.log('No search string provided!!!');
// return false; // Returning false instead of [] because no search was performed.
// }
if (fulltext_search_qry_str || ft_file_search_qry_str) {
params_json['ft_qry'] = {};
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2) {
params_json['ft_qry']['default_qry_str'] = fulltext_search_qry_str;
}
if (ft_file_search_qry_str && ft_file_search_qry_str.length > 2) {
params_json['ft_qry']['event_file_li_qry_str'] = ft_file_search_qry_str;
}
}
// Use the AND (AND LIKE) query
// if (like_search_qry_str || like_file_search_qry_str) {
// params_json['and_like'] = {};
// if (like_search_qry_str && like_search_qry_str.length > 2) {
// params_json['and_like']['default_qry_str'] = like_search_qry_str;
// }
// if (like_file_search_qry_str && like_file_search_qry_str.length > 2) {
// params_json['and_like']['event_file_li_qry_str'] = like_file_search_qry_str;
// }
// }
// Use the AND (OR LIKE) query
// if (like_search_qry_str || like_presentation_search_qry_str || like_file_search_qry_str) {
// params_json['or_like'] = {};
// if (like_search_qry_str && like_search_qry_str.length > 2) {
// params_json['or_like']['default_qry_str'] = like_search_qry_str;
// }
// if (like_presentation_search_qry_str && like_presentation_search_qry_str.length > 2) {
// params_json['or_like']['event_presentation_li_qry_str'] = like_presentation_search_qry_str;
// }
// if (like_file_search_qry_str && like_file_search_qry_str.length > 2) {
// params_json['or_like']['event_file_li_qry_str'] = like_file_search_qry_str;
// }
// }
// params_json['and_qry'] = {};
// if (created_on) {
// params_json['and_qry']['created_on'] = created_on;
// }
ae_promises.load__event_file_obj_li = await api.get_ae_obj_li_for_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_file',
for_obj_type: 'event',
for_obj_id: event_id,
use_alt_table: true, // NOTE: We want to use the alt table for file searching?
use_alt_base: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (event_file_obj_li_get_result) {
if (event_file_obj_li_get_result) {
db_save_ae_obj_li__event_file({obj_type: 'event_file', obj_li: event_file_obj_li_get_result});
return event_file_obj_li_get_result;
} else {
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
});
if (log_lvl) {
console.log('ae_promises.load__event_file_obj_li:', ae_promises.load__event_file_obj_li);
}
return ae_promises.load__event_file_obj_li;
}
// This function will loop through the event_file_obj_li and save each one to the DB.
export function db_save_ae_obj_li__event_file(
{
obj_type,
obj_li,
log_lvl=0
}: {
obj_type: string,
obj_li: any,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** db_save_ae_obj_li__event_file() ***`);
}
if (obj_li && obj_li.length) {
obj_li.forEach(async function (obj: any) {
if (log_lvl) {
console.log(`ae_obj ${obj_type}:`, obj);
}
try {
const id_random = await db_events.files.put({
id: obj.event_file_id_random,
id_random: obj.event_file_id_random,
event_file_id: obj.event_file_id_random,
event_file_id_random: obj.event_file_id_random,
hosted_file_id: obj.hosted_file_id_random,
hosted_file_id_random: obj.hosted_file_id_random,
hash_sha256: obj.hash_sha256, // Renamed with alias in FastAPI model
for_type: obj.for_type,
for_id: obj.for_id_id_random,
for_id_random: obj.for_id_random,
event_id_random: obj.event_id_random,
event_session_id_random: obj.event_session_id_random,
event_presentation_id_random: obj.event_presentation_id_random,
event_presenter_id_random: obj.event_presenter_id_random,
event_location_id_random: obj.event_location_id_random,
filename: obj.filename,
extension: obj.extension,
open_in_os: obj.open_in_os,
lu_file_purpose_id: obj.lu_file_purpose_id, // Not id_random in this case?
lu_event_file_purpose_name: obj.lu_event_file_purpose_name,
file_purpose: obj.file_purpose,
enable: obj.enable,
hide: obj.hide,
priority: obj.priority,
sort: obj.sort,
group: obj.group,
notes: obj.notes,
created_on: obj.created_on,
updated_on: obj.updated_on,
filename_no_ext: obj.filename_no_ext,
filename_w_ext: obj.filename_w_ext,
hosted_file_content_type: obj.hosted_file_content_type,
file_size: obj.file_size,
hosted_file_size: obj.hosted_file_size,
event_location_code: obj.event_location_code,
event_location_name: obj.event_location_name,
event_session_code: obj.event_session_code,
event_session_name: obj.event_session_name,
event_session_start_datetime: obj.event_session_start_datetime,
event_presentation_code: obj.event_presentation_code,
event_presentation_name: obj.event_presentation_name,
event_presentation_start_datetime: obj.event_presentation_start_datetime,
event_presenter_given_name: obj.event_presenter_given_name,
event_presenter_family_name: obj.event_presenter_family_name,
event_presenter_full_name: obj.event_presenter_full_name,
event_presenter_email: obj.event_presenter_email,
});
// console.log(`Put obj with ID: ${obj.event_file_id_random} or ${id_random}`);
} catch (error) {
let status = `Failed to put ${obj.event_file_id_random}: ${error}`;
console.log(status);
}
// const id_random = await db_events.files.put(obj);
// console.log(`Put obj with ID: ${obj.event_file_id_random}`);
});
return true;
}
return false;
}
export function db_update_ae_obj_id__event_file(
{
obj_type,
obj_id,
data_kv,
}: {
obj_type: string,
obj_id: string,
data_kv: key_val
}
) {
console.log(`*** db_update_ae_obj_id__event_file() ***`);
if (obj_id) {
console.log(`ae_obj ${obj_type}:`, obj_id);
try {
// db_events.files.update(obj_id, data_kv);
db_events.files.update(obj_id,
{
// for_type: data_kv.for_type,
// for_id: data_kv.for_id_id_random,
// for_id_random: data_kv.for_id_random,
// event_id_random: data_kv.event_id_random,
// event_session_id_random: data_kv.event_session_id_random,
// event_presentation_id_random: data_kv.event_presentation_id_random,
// event_presenter_id_random: data_kv.event_presenter_id_random,
// event_location_id_random: data_kv.event_location_id_random,
filename: data_kv.filename,
extension: data_kv.extension,
open_in_os: data_kv.open_in_os,
// lu_file_purpose_id: data_kv.lu_file_purpose_id, // Not id_random in this case?
// lu_event_file_purpose_name: data_kv.lu_event_file_purpose_name,
file_purpose: data_kv.file_purpose,
// enable: data_kv.enable,
// hide: data_kv.hide,
// priority: data_kv.priority,
// sort: data_kv.sort,
// group: data_kv.group,
// notes: data_kv.notes,
// created_on: data_kv.created_on,
// updated_on: data_kv.updated_on,
filename_no_ext: data_kv.filename_no_ext,
filename_w_ext: data_kv.filename_w_ext,
// hosted_file_content_type: data_kv.hosted_file_content_type,
// file_size: data_kv.file_size,
// hosted_file_size: data_kv.hosted_file_size,
// event_location_code: data_kv.event_location_code,
// event_location_name: data_kv.event_location_name,
// event_session_code: data_kv.event_session_code,
// event_session_name: data_kv.event_session_name,
// event_session_start_datetime: data_kv.event_session_start_datetime,
// event_presentation_code: data_kv.event_presentation_code,
// event_presentation_name: data_kv.event_presentation_name,
// event_presentation_start_datetime: data_kv.event_presentation_start_datetime,
// event_presenter_given_name: data_kv.event_presenter_given_name,
// event_presenter_family_name: data_kv.event_presenter_family_name,
// event_presenter_full_name: data_kv.event_presenter_full_name,
// event_presenter_email: data_kv.event_presenter_email,
}
);
console.log(`Update obj with ID: ${obj_id}`);
} catch (error) {
let status = `Failed to update ${obj_id}: ${error}`;
console.log(status);
}
// const id_random = await db_events.files.put(obj);
// console.log(`Put obj with ID: ${data_kv.event_file_id_random}`);
return true;
}
return false;
}

View File

@@ -0,0 +1,524 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import { db_events } from "$lib/db_events";
import { handle_load_ae_obj_li__event_file } from "$lib/ae_events__event_file";
import { load_ae_obj_li__event_session } from './ae_events__event_session';
let ae_promises: key_val = {};
// Updated 2024-06-10
export async function load_ae_obj_id__event_location(
{
api_cfg,
event_location_id,
inc_file_li = false,
inc_session_li = false,
try_cache=true,
log_lvl=0
}: {
api_cfg: any,
event_location_id: string,
inc_file_li?: boolean,
inc_session_li?: boolean,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** load_ae_obj_id__event_location() *** event_location_id=${event_location_id}`);
let params = {};
// $events_sess.badges.status_load__event_location_obj = 'loading';
ae_promises.load__event_location_obj = await api.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_location',
obj_id: event_location_id, // NOTE: This is the FQDN, not normally the ID.
use_alt_table: true, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value in the API config.
params: params,
log_lvl: log_lvl
})
.then(function (event_location_obj_get_result) {
if (event_location_obj_get_result) {
if (try_cache) {
// This is expecting a list
db_save_ae_obj_li__event_location({
obj_type: 'event_location',
obj_li: [event_location_obj_get_result]
});
}
return event_location_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.load__event_location_obj:', ae_promises.load__event_location_obj);
}
if (inc_file_li) {
// Load the files for the location
if (log_lvl) {
console.log(`Need to load the file list for the location now`);
}
let load_event_file_obj_li = handle_load_ae_obj_li__event_file({
api_cfg: api_cfg,
for_obj_type: 'event_location',
for_obj_id: event_location_id,
params: {qry__enabled: 'all', qry__limit: 15},
try_cache: try_cache,
log_lvl: log_lvl
})
.then((event_file_obj_li) => {
if (log_lvl) {
console.log(`event_file_obj_li = `, event_file_obj_li);
}
return event_file_obj_li;
});
if (log_lvl) {
console.log(`load_event_file_obj_li = `, load_event_file_obj_li);
}
ae_promises.load__event_location_obj.event_file_li = load_event_file_obj_li;
}
if (inc_session_li) {
// Load the sessions for the location
if (log_lvl) {
console.log(`Need to load the session list for the location now`);
}
let load_event_session_obj_li = load_ae_obj_li__event_session({
api_cfg: api_cfg,
for_obj_type: 'event_location',
for_obj_id: event_location_id,
params: {qry__enabled: 'all', qry__limit: 15},
try_cache: try_cache,
log_lvl: log_lvl
})
.then((event_session_obj_li) => {
if (log_lvl) {
console.log(`event_session_obj_li = `, event_session_obj_li);
}
// if (try_cache) {
// console.log(`ae_promises.load__event_session_obj = `, ae_promises.load__event_session_obj);
// ae_promises.load__event_session_obj.event_session_li = event_session_obj_li;
// // Re-save the session object with the new session list
// db_save_ae_obj_li__event_session({
// obj_type: 'event_session',
// obj_li: [ae_promises.load__event_session_obj]
// });
// }
return event_session_obj_li;
});
if (log_lvl) {
console.log(`load_event_session_obj_li = `, load_event_session_obj_li);
}
ae_promises.load__event_location_obj.event_session_li = load_event_session_obj_li;
}
return ae_promises.load__event_location_obj;
}
// Updated 2024-05-24
export async function load_ae_obj_li__event_location(
{
api_cfg,
event_id,
inc_file_li = false,
inc_session_li = false,
params={},
try_cache=true,
log_lvl=0
}: {
api_cfg: any,
event_id: string,
inc_file_li?: boolean,
inc_session_li?: boolean,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** load_ae_obj_li__event_location() *** event_id=${event_id}`);
let enabled: string = (params.qry__enabled ?? 'enabled'); // all, disabled, enabled
let hidden: string = (params.qry__hidden ?? 'all'); // all, hidden, not_hidden
let limit: number = (params.qry__limit ?? 99); // 99
let offset: number = (params.qry__offset ?? 0); // 0
let params_json: key_val = {};
// console.log('params_json:', params_json);
ae_promises.load__event_location_obj_li = await api.get_ae_obj_li_for_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_location',
for_obj_type: 'event',
for_obj_id: event_id,
use_alt_table: true, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value
enabled: enabled,
hidden: hidden,
order_by_li: {'priority': 'DESC', 'sort': 'DESC', 'name': 'ASC', 'code': 'ASC', 'updated_on': 'DESC', 'created_on': 'DESC'},
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (event_location_obj_li_get_result) {
if (event_location_obj_li_get_result) {
if (try_cache) {
db_save_ae_obj_li__event_location({
obj_type: 'event_location',
obj_li: event_location_obj_li_get_result
});
}
return event_location_obj_li_get_result;
} else {
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.load__event_location_obj_li:', ae_promises.load__event_location_obj_li);
}
if (inc_file_li) {
// Load the files for the locations
if (log_lvl) {
console.log(`Need to load the file list for each location now`);
}
for (let i = 0; i < ae_promises.load__event_location_obj_li.length; i++) {
let event_location_obj = ae_promises.load__event_location_obj_li[i];
let event_location_id = event_location_obj.event_location_id_random;
let load_event_file_obj_li = handle_load_ae_obj_li__event_file({
api_cfg: api_cfg,
for_obj_type: 'event_location',
for_obj_id: event_location_id,
params: {qry__enabled: 'all', qry__limit: 15},
try_cache: try_cache,
log_lvl: log_lvl
})
.then((event_file_obj_li) => {
if (log_lvl) {
console.log(`event_file_obj_li = `, event_file_obj_li);
}
return event_file_obj_li;
});
if (log_lvl) {
console.log(`load_event_file_obj_li = `, load_event_file_obj_li);
}
}
}
if (inc_session_li) {
// Load the sessions for the locations
if (log_lvl) {
console.log(`Need to load the session list for each location now`);
}
for (let i = 0; i < ae_promises.load__event_location_obj_li.length; i++) {
let event_location_obj = ae_promises.load__event_location_obj_li[i];
let event_location_id = event_location_obj.event_location_id_random;
let load_event_session_obj_li = load_ae_obj_li__event_session({
api_cfg: api_cfg,
for_obj_type: 'event_location',
for_obj_id: event_location_id,
params: {qry__enabled: 'all', qry__limit: 100},
try_cache: try_cache,
log_lvl: log_lvl
})
.then((event_session_obj_li) => {
if (log_lvl) {
console.log(`event_session_obj_li = `, event_session_obj_li);
}
return event_session_obj_li;
});
if (log_lvl) {
console.log(`load_event_session_obj_li = `, load_event_session_obj_li);
}
}
}
return ae_promises.load__event_location_obj_li;
}
export async function search__event_location(
{
api_cfg,
event_id,
fulltext_search_qry_str,
ft_presenter_search_qry_str,
like_search_qry_str = null,
like_presentation_search_qry_str = null,
like_presenter_search_qry_str = null,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
event_id: any,
fulltext_search_qry_str?: null|string,
ft_presenter_search_qry_str?: null|string,
like_search_qry_str?: null|string,
like_presentation_search_qry_str?: null|string,
like_presenter_search_qry_str?: null|string,
params?: any,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** search__event_location() *** event_id=${event_id}`);
let enabled: string = (params.qry__enabled ?? 'enabled'); // all, disabled, enabled
let hidden: string = (params.qry__hidden ?? 'not_hidden'); // all, hidden, not_hidden
let limit: number = (params.qry__limit ?? 25); // 99
let offset: number = (params.qry__offset ?? 0); // 0
let params_json: key_val = {};
if (!fulltext_search_qry_str && !like_search_qry_str) {
console.log('No search string provided!!!');
return false; // Returning false instead of [] because no search was performed.
}
if (fulltext_search_qry_str || ft_presenter_search_qry_str) {
params_json['ft_qry'] = {};
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2) {
params_json['ft_qry']['default_qry_str'] = fulltext_search_qry_str;
}
if (ft_presenter_search_qry_str && ft_presenter_search_qry_str.length > 2) {
params_json['ft_qry']['event_presenter_li_qry_str'] = ft_presenter_search_qry_str;
}
}
// Use the AND (AND LIKE) query
// if (like_search_qry_str || like_presenter_search_qry_str) {
// params_json['and_like'] = {};
// if (like_search_qry_str && like_search_qry_str.length > 2) {
// params_json['and_like']['default_qry_str'] = like_search_qry_str;
// }
// if (like_presenter_search_qry_str && like_presenter_search_qry_str.length > 2) {
// params_json['and_like']['event_presenter_li_qry_str'] = like_presenter_search_qry_str;
// }
// }
// Use the AND (OR LIKE) query
if (like_search_qry_str || like_presentation_search_qry_str || like_presenter_search_qry_str) {
params_json['or_like'] = {};
if (like_search_qry_str && like_search_qry_str.length > 2) {
params_json['or_like']['default_qry_str'] = like_search_qry_str;
}
if (like_presentation_search_qry_str && like_presentation_search_qry_str.length > 2) {
params_json['or_like']['event_presentation_li_qry_str'] = like_presentation_search_qry_str;
}
if (like_presenter_search_qry_str && like_presenter_search_qry_str.length > 2) {
params_json['or_like']['event_presenter_li_qry_str'] = like_presenter_search_qry_str;
}
}
params_json['and_qry'] = {};
// if (location_type_code) {
// params_json['and_qry']['location_type_code'] = location_type_code;
// }
let order_by_li = {'priority': 'DESC', 'sort': 'DESC', 'start_datetime': 'ASC', 'name': 'ASC', 'updated_on': 'DESC', 'created_on': 'DESC'};
ae_promises.load__event_location_obj_li = await api.get_ae_obj_li_for_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_location',
for_obj_type: 'event',
for_obj_id: event_id,
use_alt_table: true, // NOTE: We want to use the alt table for location searching
use_alt_base: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (event_location_obj_li_get_result) {
if (event_location_obj_li_get_result) {
db_save_ae_obj_li__event_location({obj_type: 'event_location', obj_li: event_location_obj_li_get_result});
return event_location_obj_li_get_result;
} else {
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
});
if (log_lvl) {
console.log('ae_promises.load__event_location_obj_li:', ae_promises.load__event_location_obj_li);
}
return ae_promises.load__event_location_obj_li;
}
// Updated 2024-06-25
export async function create_ae_obj__event_location(
{
api_cfg,
event_id,
data_kv,
params={},
log_lvl=0
}: {
api_cfg: any,
event_id: string,
data_kv: key_val,
params?: key_val,
log_lvl?: number
}
) {
console.log(`*** create_ae_obj__event_location() *** event_id=${event_id}`);
ae_promises.create__event_location = await api.create_ae_obj_crud({
api_cfg: api_cfg,
obj_type: 'event_location',
fields: {
event_id_random: event_id,
...data_kv
},
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl
})
.then(function (event_location_obj_create_result) {
if (event_location_obj_create_result) {
db_save_ae_obj_li__event_location(
{
obj_type: 'event_location',
obj_li: [event_location_obj_create_result]
});
return event_location_obj_create_result;
} else {
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
});
if (log_lvl) {
console.log('ae_promises.create__event_location:', ae_promises.create__event_location);
}
return ae_promises.create__event_location;
}
// This function will loop through the event_location_obj_li and save each one to the DB.
// Updated 2024-06-25
export function db_save_ae_obj_li__event_location(
{
obj_type,
obj_li,
log_lvl=0
}: {
obj_type: string,
obj_li: any,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** db_save_ae_obj_li__event_location() ***`);
}
if (obj_li && obj_li.length) {
obj_li.forEach(async function (obj: any) {
if (log_lvl) {
console.log(`ae_obj ${obj_type}:`, obj);
}
try {
const id_random = await db_events.locations.put({
id: obj.event_location_id_random,
event_location_id: obj.event_location_id_random,
event_location_id_random: obj.event_location_id_random,
external_id: obj.external_id,
code: obj.code,
type_code: obj.type_code,
event_id: obj.event_id_random,
event_id_random: obj.event_id_random,
name: obj.name,
description: obj.description,
passcode: obj.passcode,
hide_event_launcher: obj.hide_event_launcher,
alert: obj.alert,
alert_msg: obj.alert_msg,
data_json: obj.data_json,
enable: obj.enable,
hide: obj.hide,
priority: obj.priority,
sort: obj.sort,
group: obj.group,
notes: obj.notes,
created_on: obj.created_on,
updated_on: obj.updated_on,
// From SQL view
file_count: obj.file_count,
file_count_all: obj.file_count_all,
internal_use_count: obj.internal_use_count,
event_file_id_li_json: obj.event_file_id_li_json,
// poc_person_given_name: obj.poc_person_given_name,
// poc_person_family_name: obj.poc_person_family_name,
// poc_person_full_name: obj.poc_person_full_name,
// poc_person_primary_email: obj.poc_person_primary_email,
// poc_person_passcode: obj.poc_person_passcode,
// poc_kv_json: obj.poc_kv_json,
event_name: obj.event_name,
});
// console.log(`Put obj with ID: ${obj.event_location_id_random} or ${id_random}`);
} catch (error) {
let status = `Failed to put ${obj.event_location_id_random}: ${error}`;
console.log(status);
}
// const id_random = await db_events.locations.put(obj);
// console.log(`Put obj with ID: ${obj.event_location_id_random}`);
});
return true;
}
}

View File

@@ -0,0 +1,309 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import { db_events } from "$lib/db_events";
let ae_promises: key_val = {};
// Updated 2024-06-20
export async function load_ae_obj_id__event_presentation(
{
api_cfg,
event_presentation_id,
inc_file_li = false,
inc_presenter_li = false,
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
event_presentation_id: string,
inc_file_li?: boolean,
inc_presenter_li?: boolean
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** load_ae_obj_id__event_presentation() *** event_presentation_id=${event_presentation_id}`);
let params = {};
ae_promises.load__event_presentation_obj = await api.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_presentation',
obj_id: event_presentation_id, // NOTE: This is the FQDN, not normally the ID.
use_alt_table: false, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value
params: params,
log_lvl: log_lvl
})
.then(function (event_presentation_obj_get_result) {
if (event_presentation_obj_get_result) {
if (try_cache) {
// This is expecting a list
db_save_ae_obj_li__event_presentation({
obj_type: 'event_presentation',
obj_li: [event_presentation_obj_get_result]
});
}
return event_presentation_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
if (inc_file_li) {
// Load the files for the presentation
if (log_lvl) {
console.log(`Need to load the file list for the presentation now.`);
}
}
if (inc_presenter_li) {
// Load the presenters for the presentation
if (log_lvl) {
console.log(`Need to load the presenter list for the presentation now.`);
}
}
return ae_promises.load__event_presentation_obj;
}
// Updated 2024-06-10
export async function load_ae_obj_li__event_presentation(
{
api_cfg,
for_obj_type,
for_obj_id,
inc_file_li = false,
inc_presenter_li = false,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
for_obj_type: string,
for_obj_id: string,
inc_file_li?: boolean,
inc_presenter_li?: boolean
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** load_ae_obj_li__event_presentation() *** for_obj_type=${for_obj_type} for_obj_id=${for_obj_id}`);
let enabled: string = (params.qry__enabled ?? 'enabled'); // all, disabled, enabled
let hidden: string = (params.qry__hidden ?? 'not_hidden'); // all, hidden, not_hidden
let limit: number = (params.qry__limit ?? 99); // 99
let offset: number = (params.qry__offset ?? 0); // 0
let params_json: key_val = {};
// console('params_json:', params_json);
ae_promises.load__event_presentation_obj_li = await api.get_ae_obj_li_for_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_presentation',
for_obj_type: for_obj_type,
for_obj_id: for_obj_id,
use_alt_table: true, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value
enabled: enabled,
hidden: hidden,
order_by_li: {'priority': 'DESC', 'sort': 'DESC', 'start_datetime': 'ASC', 'name': 'ASC', 'updated_on': 'DESC', 'created_on': 'DESC'},
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (event_presentation_obj_li_get_result) {
if (event_presentation_obj_li_get_result) {
if (try_cache) {
db_save_ae_obj_li__event_presentation({
obj_type: 'event_presentation', obj_li: event_presentation_obj_li_get_result
});
}
return event_presentation_obj_li_get_result;
} else {
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.load__event_presentation_obj_li:', ae_promises.load__event_presentation_obj_li);
}
if (inc_file_li) {
// Load the files for the presentations
if (log_lvl) {
console.log(`Need to load the file list for each presentation now.`);
}
}
if (inc_presenter_li) {
// Load the presenters for the presentations
if (log_lvl) {
console.log(`Need to load the presenter list for each presentation now.`);
}
}
return ae_promises.load__event_presentation_obj_li;
}
// Updated 2024-06-24
export async function create_ae_obj__event_presentation(
{
api_cfg,
event_id,
event_session_id,
data_kv,
params={},
log_lvl=0
}: {
api_cfg: any,
event_id: string,
event_session_id: string,
data_kv: key_val,
params?: key_val,
log_lvl?: number
}
) {
console.log(`*** create_ae_obj__event_presentation() *** event_id=${event_id} event_session_id=${event_session_id}`);
ae_promises.create__event_presentation = await api.create_ae_obj_crud({
api_cfg: api_cfg,
obj_type: 'event_presentation',
fields: {
event_id_random: event_id,
event_session_id_random: event_session_id,
...data_kv
},
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl
})
.then(function (event_presentation_obj_create_result) {
if (event_presentation_obj_create_result) {
db_save_ae_obj_li__event_presentation(
{
obj_type: 'event_presentation',
obj_li: [event_presentation_obj_create_result]
});
return event_presentation_obj_create_result;
} else {
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
});
if (log_lvl) {
console.log('ae_promises.create__event_presentation:', ae_promises.create__event_presentation);
}
return ae_promises.create__event_presentation;
}
// This function will loop through the event_presentation_obj_li and save each one to the DB.
// Updated 2024-06-10
export function db_save_ae_obj_li__event_presentation(
{
obj_type,
obj_li,
log_lvl=0
}: {
obj_type: string,
obj_li: any,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** db_save_ae_obj_li__event_presentation() ***`);
}
if (obj_li && obj_li.length) {
obj_li.forEach(async function (obj: any) {
if (log_lvl) {
console.log(`ae_obj ${obj_type}:`, obj);
}
try {
const id_random = await db_events.presentations.put({
id: obj.event_presentation_id_random,
// id_random: obj.event_presentation_id_random,
event_presentation_id: obj.event_presentation_id_random,
event_presentation_id_random: obj.event_presentation_id_random,
external_id: obj.external_id,
code: obj.code,
for_type: obj.for_type,
for_id: obj.for_id_random,
for_id_random: obj.for_id_random,
type_code: obj.type_code,
event_id: obj.event_id_random,
event_id_random: obj.event_id_random,
event_session_id: obj.event_session_id_random,
event_session_id_random: obj.event_session_id_random,
event_abstract_id: obj.event_abstract_id_random,
event_abstract_id_random: obj.event_abstract_id_random,
abstract_code: obj.abstract_code,
name: obj.name,
description: obj.description,
start_datetime: obj.start_datetime,
end_datetime: obj.end_datetime,
passcode: obj.passcode,
hide_event_launcher: obj.hide_event_launcher,
enable: obj.enable,
hide: obj.hide,
priority: obj.priority,
sort: obj.sort,
group: obj.group,
notes: obj.notes,
created_on: obj.created_on,
updated_on: obj.updated_on,
// From SQL view
event_session_code: obj.event_session_code,
event_session_name: obj.event_session_name,
// A key value list of the presenters
// event_presenter_kv: obj.event_presenter_kv,
});
// console.log(`Put obj with ID: ${obj.event_presentation_id_random} or ${id_random}`);
} catch (error) {
let status = `Failed to put ${obj.event_presentation_id_random}: ${error}`;
console.log(status);
}
// const id_random = await db_events.presentations.put(obj);
// console.log(`Put obj with ID: ${obj.event_presentation_id_random}`);
});
return true;
}
}

View File

@@ -0,0 +1,609 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import { db_events } from "$lib/db_events";
let ae_promises: key_val = {};
// Updated 2024-06-13
export async function load_ae_obj_id__event_presenter(
{
api_cfg,
event_presenter_id,
try_cache = true,
log_lvl=0
}: {
api_cfg: any,
event_presenter_id: string,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** load_ae_obj_id__event_presenter() *** event_presenter_id=${event_presenter_id}`);
let params = {};
ae_promises.load__event_presenter_obj = await api.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_presenter',
obj_id: event_presenter_id, // NOTE: This is the FQDN, not normally the ID.
use_alt_table: true, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value
params: params,
log_lvl: log_lvl
})
.then(function (event_presenter_obj_get_result) {
if (event_presenter_obj_get_result) {
if (try_cache) {
// This is expecting a list
db_save_ae_obj_li__event_presenter({
obj_type: 'event_presenter',
obj_li: [event_presenter_obj_get_result]
});
}
return event_presenter_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
return ae_promises.load__event_presenter_obj;
}
// Updated 2024-06-10
export async function load_ae_obj_li__event_presenter(
{
api_cfg,
for_obj_type,
for_obj_id,
params={},
try_cache=true,
log_lvl=0
}: {
api_cfg: any,
for_obj_type: string,
for_obj_id: string,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** load_ae_obj_li__event_presenter() *** for_obj_type=${for_obj_type} for_obj_id=${for_obj_id}`);
}
let enabled: string = (params.qry__enabled ?? 'enabled'); // all, disabled, enabled
let hidden: string = (params.qry__hidden ?? 'not_hidden'); // all, hidden, not_hidden
let limit: number = (params.qry__limit ?? 99); // 99
let offset: number = (params.qry__offset ?? 0); // 0
let params_json: key_val = {};
// console.log('params_json:', params_json);
ae_promises.load__event_presenter_obj_li = await api.get_ae_obj_li_for_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_presenter',
for_obj_type: for_obj_type,
for_obj_id: for_obj_id,
use_alt_table: true, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value
enabled: enabled,
hidden: hidden,
order_by_li: {'priority': 'DESC', 'sort': 'DESC', 'given_name': 'ASC', 'family_name': 'ASC', 'updated_on': 'DESC', 'created_on': 'DESC'},
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (event_presenter_obj_li_get_result) {
if (event_presenter_obj_li_get_result) {
if (try_cache) {
db_save_ae_obj_li__event_presenter({
obj_type: 'event_presenter',
obj_li: event_presenter_obj_li_get_result
});
}
return event_presenter_obj_li_get_result;
} else {
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.load__event_presenter_obj_li:', ae_promises.load__event_presenter_obj_li);
}
return ae_promises.load__event_presenter_obj_li;
}
// Updated 2024-08-07
export async function delete_ae_obj_id__event_presenter(
{
api_cfg,
event_presenter_id,
method='delete', // 'delete', 'disable', 'hide'
params={},
log_lvl=0
}: {
api_cfg: any,
event_presenter_id: string,
method?: string,
params?: key_val,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** delete_ae_obj_id__event_presenter() *** event_presenter_id=${event_presenter_id}`);
}
ae_promises.delete__event_presenter_obj = await api.delete_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_presenter',
obj_id: event_presenter_id, // NOTE: This is the FQDN, not normally the ID.
key: api_cfg.api_crud_super_key,
params: params,
method: method,
log_lvl: log_lvl
})
.then(function (event_presenter_obj_delete_result) {
if (event_presenter_obj_delete_result) {
// db_save_ae_obj_li__event_presenter({obj_type: 'event_presenter', obj_li: [event_presenter_obj_delete_result]});
return event_presenter_obj_delete_result;
} else {
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
db_events.presenters.delete(event_presenter_id);
});
if (log_lvl) {
console.log('ae_promises.delete__event_presenter_obj:', ae_promises.delete__event_presenter_obj);
}
return ae_promises.delete__event_presenter_obj;
}
// Updated 2024-06-24
export async function create_ae_obj__event_presenter(
{
api_cfg,
event_id,
event_session_id,
event_presentation_id,
data_kv,
params={},
log_lvl=0
}: {
api_cfg: any,
event_id: string,
event_session_id: string,
event_presentation_id: string,
data_kv: key_val,
params?: key_val,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** create_ae_obj__event_presenter() *** event_id=${event_id} event_session_id=${event_session_id} event_presentation_id=${event_presentation_id}`);
}
ae_promises.create__event_presenter = await api.create_ae_obj_crud({
api_cfg: api_cfg,
obj_type: 'event_presenter',
fields: {
event_id_random: event_id,
event_session_id_random: event_session_id,
event_presentation_id_random: event_presentation_id,
...data_kv
},
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl
})
.then(function (event_presenter_obj_create_result) {
if (event_presenter_obj_create_result) {
db_save_ae_obj_li__event_presenter(
{
obj_type: 'event_presenter', obj_li: [event_presenter_obj_create_result]
});
return event_presenter_obj_create_result;
} else {
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
});
if (log_lvl) {
console.log('ae_promises.create__event_presenter:', ae_promises.create__event_presenter);
}
return ae_promises.create__event_presenter;
}
// Updated 2024-06-13
export async function update_ae_obj__event_presenter(
{
api_cfg,
event_presenter_id,
data_kv,
params={},
log_lvl=0
}: {
api_cfg: any,
event_presenter_id: string,
data_kv: key_val,
params?: key_val,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** update_ae_obj__event_presenter() *** event_presenter_id=${event_presenter_id}`);
}
ae_promises.update__event_presenter_obj = await api.update_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_presenter',
obj_id: event_presenter_id, // NOTE: This is the FQDN, not normally the ID.
fields: data_kv,
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl
})
.then(function (event_presenter_obj_update_result) {
if (event_presenter_obj_update_result) {
db_save_ae_obj_li__event_presenter({obj_type: 'event_presenter', obj_li: [event_presenter_obj_update_result]});
return event_presenter_obj_update_result;
} else {
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
});
if (log_lvl) {
console.log('ae_promises.update__event_presenter_obj:', ae_promises.update__event_presenter_obj);
}
return ae_promises.update__event_presenter_obj;
}
// Updated 2024-07-11
export async function search__event_presenter(
{
api_cfg,
event_id,
agree = null,
biography = null,
fulltext_search_qry_str,
ft_presenter_search_qry_str,
like_search_qry_str = null,
like_presentation_search_qry_str = null,
like_presenter_search_qry_str = null,
order_by_li = {'priority': 'DESC', 'sort': 'DESC', 'given_name': 'ASC', 'family_name': 'ASC', 'email': 'ASC', 'updated_on': 'DESC', 'created_on': 'DESC'},
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
event_id: any,
agree?: null|boolean,
biography?: null|boolean,
fulltext_search_qry_str?: null|string,
ft_presenter_search_qry_str?: null|string,
like_search_qry_str?: null|string,
like_presentation_search_qry_str?: null|string,
like_presenter_search_qry_str?: null|string,
order_by_li?: key_val,
params?: any,
try_cache?: boolean,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** search__event_presenter() *** event_id=${event_id}`);
}
let enabled: string = (params.qry__enabled ?? 'enabled'); // all, disabled, enabled
let hidden: string = (params.qry__hidden ?? 'not_hidden'); // all, hidden, not_hidden
let limit: number = (params.qry__limit ?? 25); // 99
let offset: number = (params.qry__offset ?? 0); // 0
let params_json: key_val = {};
// if (!fulltext_search_qry_str && !like_search_qry_str) {
// console.log('No search string provided!!!');
// return false; // Returning false instead of [] because no search was performed.
// }
if (fulltext_search_qry_str || ft_presenter_search_qry_str) {
params_json['ft_qry'] = {};
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2) {
params_json['ft_qry']['default_qry_str'] = fulltext_search_qry_str;
}
if (ft_presenter_search_qry_str && ft_presenter_search_qry_str.length > 2) {
params_json['ft_qry']['event_presenter_li_qry_str'] = ft_presenter_search_qry_str;
}
}
// Use the AND (AND LIKE) query
// if (like_search_qry_str || like_presenter_search_qry_str) {
// params_json['and_like'] = {};
// if (like_search_qry_str && like_search_qry_str.length > 2) {
// params_json['and_like']['default_qry_str'] = like_search_qry_str;
// }
// if (like_presenter_search_qry_str && like_presenter_search_qry_str.length > 2) {
// params_json['and_like']['event_presenter_li_qry_str'] = like_presenter_search_qry_str;
// }
// }
// Use the AND (OR LIKE) query
if (like_search_qry_str || like_presentation_search_qry_str || like_presenter_search_qry_str) {
params_json['or_like'] = {};
if (like_search_qry_str && like_search_qry_str.length > 2) {
params_json['or_like']['default_qry_str'] = like_search_qry_str;
}
if (like_presentation_search_qry_str && like_presentation_search_qry_str.length > 2) {
params_json['or_like']['event_presentation_li_qry_str'] = like_presentation_search_qry_str;
}
if (like_presenter_search_qry_str && like_presenter_search_qry_str.length > 2) {
params_json['or_like']['event_presenter_li_qry_str'] = like_presenter_search_qry_str;
}
}
params_json['and_qry'] = {};
if (agree) {
params_json['and_qry']['agree'] = agree;
}
if (biography) {
params_json['and_qry']['biography_check'] = biography;
}
ae_promises.load__event_presenter_obj_li = await api.get_ae_obj_li_for_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_presenter',
for_obj_type: 'event',
for_obj_id: event_id,
use_alt_table: true, // NOTE: We want to use the alt table for session searching
use_alt_base: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (event_presenter_obj_li_get_result) {
if (event_presenter_obj_li_get_result) {
db_save_ae_obj_li__event_presenter({obj_type: 'event_presenter', obj_li: event_presenter_obj_li_get_result});
return event_presenter_obj_li_get_result;
} else {
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
});
if (log_lvl) {
console.log('ae_promises.load__event_presenter_obj_li:', ae_promises.load__event_presenter_obj_li);
}
return ae_promises.load__event_presenter_obj_li;
}
// Updated 2024-06-10
export function db_save_ae_obj_li__event_presenter(
{
obj_type,
obj_li,
log_lvl = 0
}: {
obj_type: string,
obj_li: any,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** db_save_ae_obj_li__event_presenter() ***`);
}
if (obj_li && obj_li.length) {
obj_li.forEach(async function (obj: any) {
if (log_lvl) {
console.log(`ae_obj ${obj_type}:`, obj);
}
try {
const id_random = await db_events.presenters.put({
id: obj.event_presenter_id_random,
// id_random: obj.event_presenter_id_random,
event_presenter_id: obj.event_presenter_id_random,
event_presenter_id_random: obj.event_presenter_id_random,
external_id: obj.external_id,
code: obj.code,
// for_type: obj.for_type,
// for_id_random: obj.for_id_random,
event_id: obj.event_id_random,
event_id_random: obj.event_id_random,
event_session_id: obj.event_session_id_random,
event_session_id_random: obj.event_session_id_random,
event_presentation_id: obj.event_presentation_id_random,
event_presentation_id_random: obj.event_presentation_id_random,
event_person_id: obj.event_person_id_random,
event_person_id_random: obj.event_person_id_random,
person_id: obj.person_id_random,
person_id_random: obj.person_id_random,
person_profile_id: obj.person_profile_id_random,
person_profile_id_random: obj.person_profile_id_random, // The new table person_profile will be used soon...
pronouns: obj.pronouns,
informal_name: obj.informal_name,
title_names: obj.title_names,
given_name: obj.given_name,
middle_name: obj.middle_name,
family_name: obj.family_name,
designations: obj.designations,
professional_title: obj.professional_title,
full_name: obj.full_name,
affiliations: obj.affiliations,
email: obj.email,
biography: obj.biography,
agree: obj.agree,
comments: obj.comments,
passcode: obj.passcode,
hide_event_launcher: obj.hide_event_launcher,
data_json: obj.data_json,
enable: obj.enable,
hide: obj.hide,
priority: obj.priority,
sort: obj.sort,
group: obj.group,
notes: obj.notes,
created_on: obj.created_on,
updated_on: obj.updated_on,
// From SQL view
file_count: obj.file_count,
event_session_code: obj.event_session_code,
event_session_name: obj.event_session_name,
event_session_start_datetime: obj.event_session_start_datetime,
event_presentation_code: obj.event_presentation_code,
event_presentation_name: obj.event_presentation_name,
event_presentation_start_datetime: obj.event_presentation_start_datetime,
person_external_id: obj.person_external_id,
person_external_sys_id: obj.person_external_sys_id,
person_given_name: obj.person_given_name,
person_family_name: obj.person_family_name,
person_full_name: obj.person_full_name,
person_professional_title: obj.person_professional_title,
person_affiliations: obj.person_affiliations,
person_primary_email: obj.person_primary_email,
person_passcode: obj.person_passcode,
});
// console.log(`Put obj with ID: ${obj.event_presenter_id_random} or ${id_random}`);
} catch (error) {
let status = `Failed to put ${obj.event_presenter_id_random}: ${error}`;
console.log(status);
}
// const id_random = await db_events.presenters.put(obj);
// console.log(`Put obj with ID: ${obj.event_presenter_id_random}`);
});
return true;
}
return false;
}
// Updated 2024-08-07
export async function email_sign_in__event_presenter (
{
api_cfg,
to_email,
to_name,
base_url,
person_id,
person_passcode,
event_session_id,
event_presentation_id,
event_presenter_id,
session_name,
presentation_name,
log_lvl = 0
}: {
api_cfg: any,
to_email: string,
to_name: string,
base_url: string,
person_id: string,
person_passcode: string,
event_session_id: string,
event_presentation_id: string,
event_presenter_id: string,
session_name: string,
presentation_name: string,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** email_sign_in__event_presenter() *** to_email=${to_email} to_name=${to_name} person_id=${person_id} person_passcode=${person_passcode} presentation_id=${event_presentation_id} presenter_id=${event_presenter_id}`);
}
let subject = `LCI Congress 2024 - Pres Mgmt Hub Sign In Link for ${session_name} (ID: ${event_session_id})`;
let sign_in_url = encodeURI(`${base_url}/events_pres_mgmt/session/${event_session_id}?person_id=${person_id}&person_pass=${person_passcode}&presentation_id=${event_presentation_id}&presenter_id=${event_presenter_id}`)
let body_html = `
<div>${to_name},
<p>Your link to sign into the presentation management hub for LCI Congress 2024 is below. If you did not request this, please delete and ignore this email. If you need to make any changes or updates to your submission, you may use this link again later.</p>
</div>
<div>
<strong>26th Annual Lean Construction Congress (2024)</strong>:<br>
<p>
Session Name: ${session_name}<br>
Session ID: ${event_session_id}<br>
Presentation Name: ${presentation_name}<br>
Presentation ID: ${event_presentation_id}
</p>
<p>Use this link to view or update your LCI 2024 presentation information.<br>
Copy and paste link: <a href="${sign_in_url}">${sign_in_url}</a></p>
</div>`;
api.send_email({
api_cfg: api_cfg,
from_email: 'noreply+presmgmt@oneskyit.com',
from_name: 'LCI 2024 Pres Mgmt Hub',
to_email: to_email,
subject: subject,
body_html: body_html,
});
}

View File

@@ -0,0 +1,681 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import { db_events } from "$lib/db_events";
import { handle_load_ae_obj_li__event_file } from "$lib/ae_events__event_file";
import { load_ae_obj_li__event_presentation } from "$lib/ae_events__event_presentation";
let ae_promises: key_val = {};
// Updated 2024-08-09
export async function load_ae_obj_id__event_session(
{
api_cfg,
event_session_id,
inc_file_li = false,
inc_presentation_li = false,
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
event_session_id: string,
inc_file_li?: boolean,
inc_presentation_li?: boolean,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** load_ae_obj_id__event_session() *** event_session_id=${event_session_id}`);
let params = {};
// $events_sess.badges.status_load__event_session_obj = 'loading';
ae_promises.load__event_session_obj = await api.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_session',
obj_id: event_session_id, // NOTE: This is the FQDN, not normally the ID.
use_alt_table: true, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value in the API config.
params: params,
log_lvl: log_lvl
})
.then(function (event_session_obj_get_result) {
if (event_session_obj_get_result) {
if (try_cache) {
// This is expecting a list
db_save_ae_obj_li__event_session({
obj_type: 'event_session',
obj_li: [event_session_obj_get_result]
});
}
return event_session_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.load__event_session_obj:', ae_promises.load__event_session_obj);
}
if (inc_file_li) {
// Load the files for the session
if (log_lvl) {
console.log(`Need to load the file list for the session now`);
}
let load_event_file_obj_li = handle_load_ae_obj_li__event_file({
api_cfg: api_cfg,
for_obj_type: 'event_session',
for_obj_id: event_session_id,
params: {qry__enabled: 'all', qry__limit: 15},
try_cache: try_cache,
log_lvl: log_lvl
})
.then((event_file_obj_li) => {
if (log_lvl) {
console.log(`event_file_obj_li = `, event_file_obj_li);
}
return event_file_obj_li;
});
if (log_lvl) {
console.log(`load_event_file_obj_li = `, load_event_file_obj_li);
}
ae_promises.load__event_session_obj.event_file_li = load_event_file_obj_li;
}
if (inc_presentation_li) {
// Load the presentations for the session
if (log_lvl) {
console.log(`Need to load the presentation list for the session now`);
}
let load_event_presentation_obj_li = load_ae_obj_li__event_presentation({
api_cfg: api_cfg,
event_session_id: event_session_id,
params: {qry__enabled: 'all', qry__limit: 25},
try_cache: try_cache,
log_lvl: log_lvl
})
.then((event_presentation_obj_li) => {
if (log_lvl) {
console.log(`event_presentation_obj_li = `, event_presentation_obj_li);
}
// if (try_cache) {
// console.log(`ae_promises.load__event_session_obj = `, ae_promises.load__event_session_obj);
// ae_promises.load__event_session_obj.event_presentation_li = event_presentation_obj_li;
// // Re-save the session object with the new presentation list
// db_save_ae_obj_li__event_session({
// obj_type: 'event_session',
// obj_li: [ae_promises.load__event_session_obj]
// });
// }
return event_presentation_obj_li;
});
if (log_lvl) {
console.log(`event_presentation_obj_li = `, load_event_presentation_obj_li);
}
ae_promises.load__event_session_obj.event_presentation_li = load_event_presentation_obj_li;
}
return ae_promises.load__event_session_obj;
}
// Updated 2024-08-09
export async function load_ae_obj_li__event_session(
{
api_cfg,
for_obj_type,
for_obj_id,
inc_file_li = false,
inc_presentation_li = false,
order_by_li = {'priority': 'DESC', 'sort': 'DESC', 'start_datetime': 'ASC', 'name': 'ASC', 'updated_on': 'DESC', 'created_on': 'DESC'},
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
for_obj_type: string,
for_obj_id: string,
inc_file_li?: boolean,
inc_presentation_li?: boolean,
order_by_li?: key_val,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** load_ae_obj_li__event_session() *** for_obj_type=${for_obj_type} for_obj_id=${for_obj_id}`);
let enabled: string = (params.qry__enabled ?? 'enabled'); // all, disabled, enabled
let hidden: string = (params.qry__hidden ?? 'not_hidden'); // all, hidden, not_hidden
let limit: number = (params.qry__limit ?? 99); // 99
let offset: number = (params.qry__offset ?? 0); // 0
let params_json: key_val = {};
// console.log('params_json:', params_json);
ae_promises.load__event_session_obj_li = await api.get_ae_obj_li_for_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_session',
for_obj_type: for_obj_type,
for_obj_id: for_obj_id,
use_alt_table: true, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (event_session_obj_li_get_result) {
if (event_session_obj_li_get_result) {
if (try_cache) {
db_save_ae_obj_li__event_session({
obj_type: 'event_session',
obj_li: event_session_obj_li_get_result
});
}
return event_session_obj_li_get_result;
} else {
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.load__event_session_obj_li:', ae_promises.load__event_session_obj_li);
}
if (inc_file_li) {
// Load the files for the sessions
if (log_lvl) {
console.log(`Need to load the file list for each session now`);
}
for (let i = 0; i < ae_promises.load__event_session_obj_li.length; i++) {
let event_session_obj = ae_promises.load__event_session_obj_li[i];
let event_session_id = event_session_obj.event_session_id_random;
let load_event_file_obj_li = handle_load_ae_obj_li__event_file({
api_cfg: api_cfg,
for_obj_type: 'event_session',
for_obj_id: event_session_id,
params: {qry__enabled: 'all', qry__limit: 15},
try_cache: try_cache,
log_lvl: log_lvl
})
.then((event_file_obj_li) => {
if (log_lvl) {
console.log(`event_file_obj_li = `, event_file_obj_li);
}
return event_file_obj_li;
});
if (log_lvl) {
console.log(`load_event_file_obj_li = `, load_event_file_obj_li);
}
}
}
if (inc_presentation_li) {
// Load the presentations for the sessions
if (log_lvl) {
console.log(`Need to load the presentation list for each session now`);
}
for (let i = 0; i < ae_promises.load__event_session_obj_li.length; i++) {
let event_session_obj = ae_promises.load__event_session_obj_li[i];
let event_session_id = event_session_obj.event_session_id_random;
let load_event_presentation_obj_li = load_ae_obj_li__event_presentation({
api_cfg: api_cfg,
for_obj_type: 'event_session',
for_obj_id: event_session_id,
inc_file_li: false, // This will need to be changed.
inc_presenter_li: false, // This will need to be changed.
params: {qry__enabled: 'all', qry__limit: 25},
try_cache: try_cache,
log_lvl: log_lvl
})
.then((event_presentation_obj_li) => {
if (log_lvl) {
console.log(`event_presentation_obj_li = `, event_presentation_obj_li);
}
// if (try_cache) {
// console.log(`event_session_obj = `, event_session_obj);
// event_session_obj.event_presentation_li = event_presentation_obj_li;
// // Re-save the session object with the new presentation list
// db_save_ae_obj_li__event_session({
// obj_type: 'event_session',
// obj_li: event_session_obj
// });
// }
return event_presentation_obj_li;
});
if (log_lvl) {
console.log(`load_event_presentation_obj_li = `, load_event_presentation_obj_li);
}
}
}
return ae_promises.load__event_session_obj_li;
}
// This new function is using CRUD v2. This should allow for more flexibility in the queries.
// Updated 2024-08-14
export async function qry__event_session(
{
api_cfg,
event_id,
qry_str,
qry_files,
qry_start_datetime, // Example greater than: '2024-10-24'
enabled = 'enabled',
hidden = 'not_hidden',
limit = 50,
offset = 0,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
event_id: any,
qry_str?: string,
qry_files?: null|boolean,
qry_start_datetime?: null|string, // Greater than this datetime
enabled?: string, // all, disabled, enabled
hidden?: string, // all, hidden, not_hidden
limit?: number,
offset?: number,
params?: any,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** qry__event_session() *** event_id=${event_id} qry_str=${qry_str}`);
// let enabled: string = (params.qry__enabled ?? 'enabled'); // all, disabled, enabled
// let hidden: string = (params.qry__hidden ?? 'not_hidden'); // all, hidden, not_hidden
// let limit: number = (params.qry__limit ?? 25); // 99
// let offset: number = (params.qry__offset ?? 0); // 0
let params_json: key_val = {};
// if (qry_str && qry_str.length > 2) {
// params_json['ft_qry'] = {};
// params_json['ft_qry']['default_qry_str'] = qry_str;
// }
params_json['qry'] = [];
if (qry_files === true) {
let qry_param =
{
type: "AND",
field: "file_count_all",
operator: ">",
value: 0
};
params_json['qry'].push(qry_param);
} else if (qry_files === false) {
let qry_param =
{
type: "AND",
field: "file_count_all",
operator: "IS",
value: null
};
params_json['qry'].push(qry_param);
}
if (qry_start_datetime) {
let qry_param =
{
type: "AND",
field: "start_datetime",
operator: ">",
value: qry_start_datetime
};
params_json['qry'].push(qry_param);
}
let order_by_li = {'priority': 'DESC', 'sort': 'DESC', 'start_datetime': 'ASC', 'name': 'ASC', 'updated_on': 'DESC', 'created_on': 'DESC'};
ae_promises.load__event_session_obj_li = await api.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg: api_cfg,
obj_type: 'event_session',
for_obj_type: 'event',
for_obj_id: event_id,
use_alt_tbl: true, // NOTE: We want to use the alt table for session searching
use_alt_mdl: false,
use_alt_exp: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (event_session_obj_li_get_result) {
if (event_session_obj_li_get_result) {
db_save_ae_obj_li__event_session({obj_type: 'event_session', obj_li: event_session_obj_li_get_result});
return event_session_obj_li_get_result;
} else {
return [];
}
});
if (log_lvl) {
console.log('ae_promises.load__event_session_obj_li:', ae_promises.load__event_session_obj_li);
}
return ae_promises.load__event_session_obj_li;
}
export async function search__event_session(
{
api_cfg,
event_id,
fulltext_search_qry_str,
ft_presenter_search_qry_str,
like_search_qry_str = null,
like_presentation_search_qry_str = null,
like_presenter_search_qry_str = null,
file_count = false, // If true then only show those that have a file count
location_name = null,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
event_id: any,
fulltext_search_qry_str?: null|string,
ft_presenter_search_qry_str?: null|string,
like_search_qry_str?: null|string,
like_presentation_search_qry_str?: null|string,
like_presenter_search_qry_str?: null|string,
file_count?: boolean,
location_name?: null|string,
params?: any,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** search__event_session() *** event_id=${event_id}`);
let enabled: string = (params.qry__enabled ?? 'enabled'); // all, disabled, enabled
let hidden: string = (params.qry__hidden ?? 'not_hidden'); // all, hidden, not_hidden
let limit: number = (params.qry__limit ?? 25); // 99
let offset: number = (params.qry__offset ?? 0); // 0
let params_json: key_val = {};
if (!fulltext_search_qry_str && !like_search_qry_str) {
console.log('No search string provided!!!');
return false; // Returning false instead of [] because no search was performed.
}
if (fulltext_search_qry_str || ft_presenter_search_qry_str) {
params_json['ft_qry'] = {};
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2) {
params_json['ft_qry']['default_qry_str'] = fulltext_search_qry_str;
}
if (ft_presenter_search_qry_str && ft_presenter_search_qry_str.length > 2) {
params_json['ft_qry']['event_presenter_li_qry_str'] = ft_presenter_search_qry_str;
}
}
// Use the AND (AND LIKE) query
// if (like_search_qry_str || like_presenter_search_qry_str) {
// params_json['and_like'] = {};
// if (like_search_qry_str && like_search_qry_str.length > 2) {
// params_json['and_like']['default_qry_str'] = like_search_qry_str;
// }
// if (like_presenter_search_qry_str && like_presenter_search_qry_str.length > 2) {
// params_json['and_like']['event_presenter_li_qry_str'] = like_presenter_search_qry_str;
// }
// }
// Use the AND (OR LIKE) query
if (like_search_qry_str || like_presentation_search_qry_str || like_presenter_search_qry_str) {
params_json['or_like'] = {};
if (like_search_qry_str && like_search_qry_str.length > 2) {
params_json['or_like']['default_qry_str'] = like_search_qry_str;
}
if (like_presentation_search_qry_str && like_presentation_search_qry_str.length > 2) {
params_json['or_like']['event_presentation_li_qry_str'] = like_presentation_search_qry_str;
}
if (like_presenter_search_qry_str && like_presenter_search_qry_str.length > 2) {
params_json['or_like']['event_presenter_li_qry_str'] = like_presenter_search_qry_str;
}
}
params_json['and_qry'] = {};
if (file_count) {
params_json['and_qry']['file_count'] = file_count;
}
// This should be using a like with surrounded by %'s
if (location_name) {
params_json['and_qry']['event_location_name'] = location_name;
}
let order_by_li = {'priority': 'DESC', 'sort': 'DESC', 'start_datetime': 'ASC', 'name': 'ASC', 'updated_on': 'DESC', 'created_on': 'DESC'};
ae_promises.load__event_session_obj_li = await api.get_ae_obj_li_for_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_session',
for_obj_type: 'event',
for_obj_id: event_id,
use_alt_table: true, // NOTE: We want to use the alt table for session searching
use_alt_base: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (event_session_obj_li_get_result) {
if (event_session_obj_li_get_result) {
db_save_ae_obj_li__event_session({obj_type: 'event_session', obj_li: event_session_obj_li_get_result});
return event_session_obj_li_get_result;
} else {
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
});
if (log_lvl) {
console.log('ae_promises.load__event_session_obj_li:', ae_promises.load__event_session_obj_li);
}
return ae_promises.load__event_session_obj_li;
}
// This function will loop through the event_session_obj_li and save each one to the DB.
export function db_save_ae_obj_li__event_session(
{
obj_type,
obj_li,
log_lvl = 0
}: {
obj_type: string,
obj_li: any,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** db_save_ae_obj_li__event_session() ***`);
}
if (obj_li && obj_li.length) {
obj_li.forEach(async function (obj: any) {
if (log_lvl) {
console.log(`ae_obj ${obj_type}:`, obj);
}
try {
const id_random = await db_events.sessions.put({
id: obj.event_session_id_random,
event_session_id: obj.event_session_id_random,
event_session_id_random: obj.event_session_id_random,
external_id: obj.external_id,
code: obj.code,
for_type: obj.for_type,
for_id: obj.for_id_id_random,
for_id_random: obj.for_id_random,
type_code: obj.type_code,
event_id: obj.event_id_random,
event_id_random: obj.event_id_random,
event_location_id: obj.event_location_id_random,
event_location_id_random: obj.event_location_id_random,
poc_person_id: obj.poc_person_id_random,
poc_person_id_random: obj.poc_person_id_random,
name: obj.name,
description: obj.description,
start_datetime: obj.start_datetime,
end_datetime: obj.end_datetime,
passcode: obj.passcode,
hide_event_launcher: obj.hide_event_launcher,
alert: obj.alert,
alert_msg: obj.alert_msg,
data_json: obj.data_json,
ux_mode: obj.ux_mode,
enable: obj.enable,
hide: obj.hide,
priority: obj.priority,
sort: obj.sort,
group: obj.group,
notes: obj.notes,
created_on: obj.created_on,
updated_on: obj.updated_on,
// From SQL view
file_count: obj.file_count,
file_count_all: obj.file_count_all,
internal_use_count: obj.internal_use_count,
event_file_id_li_json: obj.event_file_id_li_json,
poc_person_given_name: obj.poc_person_given_name,
poc_person_family_name: obj.poc_person_family_name,
poc_person_full_name: obj.poc_person_full_name,
poc_person_primary_email: obj.poc_person_primary_email,
poc_person_passcode: obj.poc_person_passcode,
poc_kv_json: obj.poc_kv_json,
event_name: obj.event_name,
event_location_code: obj.event_location_code,
event_location_name: obj.event_location_name,
// A key value list of the presentations
event_presentation_kv: obj.event_presentation_kv,
event_presentation_li: obj.event_presentation_li,
});
// console.log(`Put obj with ID: ${obj.event_session_id_random} or ${id_random}`);
} catch (error) {
let status = `Failed to put ${obj.event_session_id_random}: ${error}`;
console.log(status);
}
// const id_random = await db_events.sessions.put(obj);
// console.log(`Put obj with ID: ${obj.event_session_id_random}`);
});
return true;
}
}
// This is intended for the Point of Contact (POC) for the session.
// Updated 2024-07-01
export async function email_sign_in__event_session (
{
api_cfg,
to_email,
to_name,
base_url,
person_id,
person_passcode,
event_session_id,
session_name,
}: {
api_cfg: any,
to_email: string,
to_name: string,
base_url: string,
person_id: string,
person_passcode: string,
event_session_id: string,
session_name: string,
}
) {
console.log(`*** email_sign_in__event_session() *** to_email=${to_email} to_name=${to_name} person_id=${person_id} person_passcode=${person_passcode} session_id=${event_session_id}`);
let subject = `LCI Congress 2024 - Pres Mgmt Hub Sign In Link for ${session_name} (ID: ${event_session_id})`;
let sign_in_url = encodeURI(`${base_url}/events_pres_mgmt/session/${event_session_id}?person_id=${person_id}&person_pass=${person_passcode}&session_id=${event_session_id}`)
let body_html = `
<div>${to_name},
<p>Your link to sign into the presentation management hub as a session Champion for LCI Congress 2024 is below. If you did not request this, please delete and ignore this email. If you need to make any changes or updates to your submission, you may use this link again later.</p>
</div>
<div>
<strong>26th Annual Lean Construction Congress (2024)</strong>:<br>
<p>
Session Name: ${session_name}<br>
Session ID: ${event_session_id}
</p>
<p>Use this link to view or update your LCI 2024 session information.<br>
Copy and paste link: <a href="${sign_in_url}">${sign_in_url}</a></p>
</div>`;
api.send_email({
api_cfg: api_cfg,
from_email: 'noreply+presmgmt@oneskyit.com',
from_name: 'LCI 2024 Pres Mgmt Hub',
to_email: to_email,
subject: subject,
body_html: body_html,
});
}

View File

@@ -0,0 +1,564 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import { db_events } from "$lib/db_events";
let ae_promises: key_val = {};
// Updated 2024-03
export async function handle_load_ae_obj_id__exhibit(
{
api_cfg,
exhibit_id,
try_cache=false,
log_lvl=0
}: {
api_cfg: any,
exhibit_id: string,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** handle_load_ae_obj_id__exhibit() *** exhibit_id=${exhibit_id}`);
let params = {};
// $events_sess.exhibits.status_load__exhibit_obj = 'loading';
ae_promises.load__exhibit_obj = await api.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_exhibit',
obj_id: exhibit_id, // NOTE: This is the FQDN, not normally the ID.
use_alt_table: false, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value in the API config.
params: params,
log_lvl: log_lvl
})
.then(function (exhibit_obj_get_result) {
if (exhibit_obj_get_result) {
// This is expecting a list
handle_db_save_ae_obj_li__exhibitor({obj_type: 'event_exhibit', obj_li: [exhibit_obj_get_result]});
return exhibit_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
return ae_promises.load__exhibit_obj;
}
// Updated 2024-03-06
export async function handle_load_ae_obj_li__exhibit(
{
api_cfg,
event_id,
params={},
try_cache=true,
log_lvl=0
}: {
api_cfg: any,
event_id: any,
params: any,
try_cache?: boolean
log_lvl?: number
}
) {
console.log(`*** handle_load_ae_obj_li__exhibit() *** event_id=${event_id}`);
let enabled: string = (params.qry__enabled ?? 'enabled'); // all, disabled, enabled
let hidden: string = (params.qry__hidden ?? 'not_hidden'); // all, hidden, not_hidden
let limit: number = (params.qry__limit ?? 99); // 99
let offset: number = (params.qry__offset ?? 0); // 0
let params_json: key_val = {};
// params_json['and_qry'] = {};
// params_json['and_qry']['license_max'] = 10;
params_json['and_in_li'] = {
license_max : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
};
// if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2) {
// params_json['ft_qry'] = {
// 'default_qry_str': fulltext_search_qry_str,
// // 'location_address_json_ext': fulltext_search_qry_str, // JSON extracted text DB field
// // 'contact_li_json_ext': fulltext_search_qry_str, // JSON extracted text DB field
// };
// }
// console.log('params_json:', params_json);
// console.log(params_json);
// $events_sess.exhibits.status_qry__search = 'loading';
ae_promises.load__event_exhibit_obj_li = await api.get_ae_obj_li_for_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_exhibit',
for_obj_type: 'event',
for_obj_id: event_id,
use_alt_table: false, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value in the API config.
enabled: enabled,
hidden: hidden,
order_by_li: {'priority': 'DESC', 'sort': 'DESC', 'updated_on': 'DESC', 'created_on': 'DESC'},
// order_by_li: {'priority': 'DESC', 'sort': 'DESC', 'created_on': 'DESC', 'updated_on': 'DESC'},
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (exhibit_obj_li_get_result) {
// console.log('Badge list:', exhibit_obj_li_get_result);
if (exhibit_obj_li_get_result) {
// $slct.exhibit_obj_li = exhibit_obj_li_get_result;
handle_db_save_ae_obj_li__exhibitor({obj_type: 'event_exhibit', obj_li: exhibit_obj_li_get_result});
return exhibit_obj_li_get_result;
} else {
// $slct.exhibit_obj_li = [];
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
// $events_sess.exhibits.status_qry__search = 'done';
// console.log('Badge list:', exhibit_obj_li_get_result);
// return exhibit_obj_li_get_result;
});
if (log_lvl) {
console.log('ae_promises.load__event_exhibit_obj_li:', ae_promises.load__event_exhibit_obj_li);
}
return ae_promises.load__event_exhibit_obj_li;
}
export async function handle_load_ae_obj_id__exhibit_tracking(
{
api_cfg,
exhibit_tracking_id,
try_cache=false,
log_lvl=0
}: {
api_cfg: any,
exhibit_tracking_id: string,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** handle_load_ae_obj_id__exhibit_tracking() *** exhibit_tracking_id=${exhibit_tracking_id}`);
let params = {};
// $events_sess.exhibits.status_load__exhibit_tracking_obj = 'loading';
ae_promises.load__event_exhibit_tracking_obj = await api.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_exhibit_tracking',
obj_id: exhibit_tracking_id, // NOTE: This is the FQDN, not normally the ID.
use_alt_table: false, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value in the API config.
params: params,
log_lvl: log_lvl
})
.then(function (exhibit_tracking_obj_get_result) {
if (exhibit_tracking_obj_get_result) {
// This is expecting a list
handle_db_save_ae_obj_li__exhibitor_tracking({obj_type: 'event_exhibit_tracking', obj_li: [exhibit_tracking_obj_get_result]});
return exhibit_tracking_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
return ae_promises.load__event_exhibit_tracking_obj;
}
// Updated 2024-03-19
export async function handle_load_ae_obj_li__exhibit_tracking(
{
api_cfg,
exhibit_id,
params={},
try_cache=true,
log_lvl=0
}: {
api_cfg: any,
exhibit_id: any,
params: any,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** handle_load_ae_obj_li__exhibit_tracking() *** exhibit_id=${exhibit_id}`);
let enabled: string = (params.qry__enabled ?? 'enabled'); // all, disabled, enabled
let hidden: string = (params.qry__hidden ?? 'all'); // all, hidden, not_hidden
let limit: number = (params.qry__limit ?? 99); // 99
let offset: number = (params.qry__offset ?? 0); // 0
let params_json: key_val = {};
ae_promises.load__event_exhibit_tracking_obj_li = await api.get_ae_obj_li_for_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_exhibit_tracking',
for_obj_type: 'event_exhibit',
for_obj_id: exhibit_id,
use_alt_table: false, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value in the API config.
enabled: enabled,
hidden: hidden,
order_by_li: {'priority': 'DESC', 'sort': 'DESC', 'updated_on': 'DESC', 'created_on': 'DESC'},
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (exhibit_tracking_obj_li_get_result) {
// console.log('Exhibit tracking list:', exhibit_tracking_obj_li_get_result);
if (exhibit_tracking_obj_li_get_result) {
// $slct.exhibit_tracking_obj_li = exhibit_tracking_obj_li_get_result;
handle_db_save_ae_obj_li__exhibitor_tracking({obj_type: 'event_exhibit_tracking', obj_li: exhibit_tracking_obj_li_get_result});
return exhibit_tracking_obj_li_get_result;
} else {
// $slct.exhibit_tracking_obj_li = [];
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
// console.log('Exhibit tracking list:', exhibit_tracking_obj_li_get_result);
// return exhibit_tracking_obj_li_get_result;
});
if (log_lvl) {
console.log('ae_promises.load__event_exhibit_tracking_obj_li:', ae_promises.load__event_exhibit_tracking_obj_li);
}
return ae_promises.load__event_exhibit_tracking_obj_li;
}
// Updated 2024-03-22
export async function handle_create_ae_obj__exhibit_tracking(
{
api_cfg,
exhibit_id,
event_badge_id,
external_person_id,
params={},
log_lvl=0
}: {
api_cfg: any,
exhibit_id: string,
event_badge_id: string,
external_person_id: string,
params: key_val,
log_lvl: number
}
) {
console.log(`*** handle_create_ae_obj__exhibit_tracking() *** exhibit_id=${exhibit_id}, event_badge_id=${event_badge_id}`);
let params_json: key_val = {};
// $events_sess.exhibits.status_create__exhibit_tracking = 'loading';
ae_promises.create__event_exhibit_tracking = await api.create_ae_obj_crud({
api_cfg: api_cfg,
obj_type: 'event_exhibit_tracking',
fields: {
event_exhibit_id_random: exhibit_id,
event_badge_id_random: event_badge_id,
external_person_id: external_person_id,
},
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl
})
.then(function (exhibit_tracking_obj_create_result) {
// console.log('Exhibit tracking create:', exhibit_tracking_obj_create_result);
if (exhibit_tracking_obj_create_result) {
// $slct.exhibit_tracking_obj = exhibit_tracking_obj_create_result;
handle_db_save_ae_obj_li__exhibitor_tracking({obj_type: 'event_exhibit_tracking', obj_li: [exhibit_tracking_obj_create_result]});
return exhibit_tracking_obj_create_result;
} else {
// $slct.exhibit_tracking_obj = [];
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
// console.log('Exhibit tracking create:', exhibit_tracking_obj_create_result);
// return exhibit_tracking_obj_create_result;
});
if (log_lvl) {
console.log('ae_promises.create__event_exhibit_tracking:', ae_promises.create__event_exhibit_tracking);
}
return ae_promises.create__event_exhibit_tracking;
}
// Updated 2024-03-28
export async function handle_update_ae_obj__exhibit_tracking(
{
api_cfg,
exhibit_tracking_id,
data,
params={},
log_lvl=0
}: {
api_cfg: any,
exhibit_tracking_id: string,
data: any,
params: key_val,
log_lvl: number
}
) {
console.log(`*** handle_update_ae_obj__exhibit_tracking() *** exhibit_tracking_id=${exhibit_tracking_id}`);
ae_promises.update__event_exhibit_tracking = await api.update_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'event_exhibit_tracking',
obj_id: exhibit_tracking_id,
fields: data,
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl
})
.then(function (exhibit_tracking_obj_update_result) {
if (exhibit_tracking_obj_update_result) {
handle_db_save_ae_obj_li__exhibitor_tracking({obj_type: 'event_exhibit_tracking', obj_li: [exhibit_tracking_obj_update_result]});
return exhibit_tracking_obj_update_result;
} else {
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
});
if (log_lvl) {
console.log('ae_promises.update__event_exhibit_tracking:', ae_promises.update__event_exhibit_tracking);
}
return ae_promises.update__event_exhibit_tracking;
}
export async function handle_download_export__event_exhibit_tracking(
{
api_cfg,
exhibit_id,
file_type='CSV', // 'CSV' or 'Excel'
return_file=true,
filename='no_filename.csv',
auto_download=false,
params={},
log_lvl=0
}: {
api_cfg: any,
exhibit_id: string,
file_type?: string,
return_file?: boolean,
filename?: string,
auto_download?: boolean,
params?: key_val,
log_lvl?: number
}
) {
console.log('*** ae_events_functions.js: get_event_exhibit_tracking_export() ***');
const endpoint = `/event/exhibit/${exhibit_id}/tracking/export`;
if (file_type == 'CSV' || file_type == 'Excel') {
params['file_type'] = file_type;
}
params['return_file'] = true;
ae_promises.download__event_exhibit_tracking_export_file = await api.get_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
return_blob: true,
filename: filename,
auto_download: auto_download,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('ae_promises.download__event_exhibit_tracking_export_file:', ae_promises.download__event_exhibit_tracking_export_file);
}
return ae_promises.download__event_exhibit_tracking_export_file;
}
// This function will loop through the event_exhibit_obj_li and save each one to the DB.
export function handle_db_save_ae_obj_li__exhibitor(
{
obj_type,
obj_li=[],
log_lvl=0
}: {
obj_type: string,
obj_li: any[],
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** handle_db_save_ae_obj_li__exhibitor() ***`);
}
if (obj_li && obj_li.length) {
obj_li.forEach(async function (obj) {
if (log_lvl) {
console.log(`ae_obj ${obj_type}:`, obj);
}
try {
const id_random = await db_events.exhibits.put({
id_random: obj.event_exhibit_id_random,
event_exhibit_id_random: obj.event_exhibit_id_random,
event_id_random: obj.event_id_random,
code: obj.code,
name: obj.name,
description: obj.description,
staff_passcode: obj.staff_passcode,
data_json: obj.data_json,
leads_api_access: obj.leads_api_access,
leads_custom_questions_json: obj.leads_custom_questions_json,
leads_device_sm_qty: obj.leads_device_sm_qty,
leads_device_lg_qty: obj.leads_device_lg_qty,
license_max: obj.license_max,
license_li_json: obj.license_li_json,
cfg_json: obj.cfg_json,
enable: obj.enable,
hide: obj.hide,
priority: obj.priority,
sort: obj.sort,
group: obj.group,
notes: obj.notes,
created_on: obj.created_on,
updated_on: obj.updated_on,
});
// console.log(`Put obj with ID: ${obj.event_exhibit_id_random} or ${id_random}`);
} catch (error) {
let status = `Failed to put ${obj.event_exhibit_id_random}: ${error}`;
console.log(status);
}
// const id_random = await db_events.exhibits.put(obj);
// console.log(`Put obj with ID: ${obj.event_exhibit_id_random}`);
});
return true;
}
}
// This function will loop through the event_exhibit_tracking_obj_li and save each one to the DB.
export function handle_db_save_ae_obj_li__exhibitor_tracking(
{
obj_type,
obj_li,
log_lvl=0
}: {
obj_type: string,
obj_li: any,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** handle_db_save_ae_obj_li__exhibitor_tracking() ***`);
}
if (obj_li && obj_li.length) {
obj_li.forEach(async function (obj: any) {
if (log_lvl) {
console.log(`ae_obj ${obj_type}:`, obj);
}
try {
const id_random = await db_events.exhibit_tracking.put({
id_random: obj.event_exhibit_tracking_id_random,
event_exhibit_tracking_id_random: obj.event_exhibit_tracking_id_random,
event_exhibit_id_random: obj.event_exhibit_id_random,
event_badge_id_random: obj.event_badge_id_random,
event_person_id_random: obj.event_person_id_random,
external_person_id: obj.external_person_id,
exhibitor_notes: obj.exhibitor_notes,
responses_json: obj.responses_json,
data_json: obj.data_json,
event_exhibit_name: obj.event_exhibit_name,
event_badge_title_names: obj.event_badge_title_names,
event_badge_given_name: obj.event_badge_given_name,
event_badge_family_name: obj.event_badge_family_name,
event_badge_designations: obj.event_badge_designations,
event_badge_full_name: obj.event_badge_full_name,
event_badge_full_name_override: obj.event_badge_full_name_override,
event_badge_professional_title: obj.event_badge_professional_title,
event_badge_professional_title_override: obj.event_badge_professional_title_override,
event_badge_affiliations: obj.event_badge_affiliations,
event_badge_affiliations_override: obj.event_badge_affiliations_override,
event_badge_email: obj.event_badge_email,
event_badge_email_override: obj.event_badge_email_override,
event_badge_location: obj.event_badge_location,
event_badge_location_override: obj.event_badge_location_override,
event_badge_country: obj.event_badge_country,
enable: obj.enable,
hide: obj.hide,
priority: obj.priority,
sort: obj.sort,
group: obj.group,
notes: obj.notes,
created_on: obj.created_on,
updated_on: obj.updated_on,
});
// console.log(`Put obj with ID: ${obj.event_exhibit_tracking_id_random} or ${id_random}`);
} catch (error) {
let status = `Failed to put ${obj.event_exhibit_tracking_id_random}: ${error}`;
console.log(status);
}
// const id_random = await db_events.exhibit_tracking.put(obj);
// console.log(`Put obj with ID: ${obj.event_exhibit_tracking_id_random}`);
});
return true;
}
}

View File

@@ -0,0 +1,126 @@
// This file is used to export all the functions that are used for Aether Events related functions.
import {
handle_load_ae_obj_id__event,
handle_load_ae_obj_li__event,
handle_db_save_ae_obj_li__event,
} from "$lib/ae_events__event";
import {
handle_load_ae_obj_id__event_file,
handle_load_ae_obj_li__event_file,
handle_delete_ae_obj_id__event_file,
create_event_file_obj_from_hosted_file_async,
handle_update_ae_obj__event_file,
search__event_file,
db_save_ae_obj_li__event_file,
} from "$lib/ae_events__event_file";
import {
handle_load_ae_obj_id__exhibit,
handle_load_ae_obj_li__exhibit,
handle_load_ae_obj_id__exhibit_tracking,
handle_load_ae_obj_li__exhibit_tracking,
handle_create_ae_obj__exhibit_tracking,
handle_update_ae_obj__exhibit_tracking,
handle_download_export__event_exhibit_tracking,
handle_db_save_ae_obj_li__exhibitor,
} from "$lib/ae_events__exhibit";
import {
load_ae_obj_id__event_location,
load_ae_obj_li__event_location,
create_ae_obj__event_location,
db_save_ae_obj_li__event_location,
} from "$lib/ae_events__event_location";
import {
load_ae_obj_id__event_session,
load_ae_obj_li__event_session,
qry__event_session,
search__event_session,
db_save_ae_obj_li__event_session,
email_sign_in__event_session,
} from "$lib/ae_events__event_session";
import {
load_ae_obj_id__event_presentation,
load_ae_obj_li__event_presentation,
create_ae_obj__event_presentation,
db_save_ae_obj_li__event_presentation,
} from "$lib/ae_events__event_presentation";
import {
load_ae_obj_id__event_presenter,
load_ae_obj_li__event_presenter,
delete_ae_obj_id__event_presenter,
create_ae_obj__event_presenter,
update_ae_obj__event_presenter,
search__event_presenter,
db_save_ae_obj_li__event_presenter,
email_sign_in__event_presenter,
} from "$lib/ae_events__event_presenter";
import {
handle_load_ae_obj_id__badge,
handle_load_ae_obj_li__badge,
handle_search__event_badge,
handle_db_save_ae_obj_li__badge,
} from "$lib/ae_events__event_badge";
let export_obj = {
handle_load_ae_obj_id__event: handle_load_ae_obj_id__event,
handle_load_ae_obj_li__event: handle_load_ae_obj_li__event,
handle_db_save_ae_obj_li__event: handle_db_save_ae_obj_li__event,
handle_load_ae_obj_id__event_file: handle_load_ae_obj_id__event_file,
handle_load_ae_obj_li__event_file: handle_load_ae_obj_li__event_file,
handle_delete_ae_obj_id__event_file: handle_delete_ae_obj_id__event_file,
handle_update_ae_obj__event_file: handle_update_ae_obj__event_file,
search__event_file: search__event_file,
db_save_ae_obj_li__event_file: db_save_ae_obj_li__event_file,
load_ae_obj_id__event_location: load_ae_obj_id__event_location,
load_ae_obj_li__event_location: load_ae_obj_li__event_location,
create_ae_obj__event_location: create_ae_obj__event_location,
db_save_ae_obj_li__event_location: db_save_ae_obj_li__event_location,
load_ae_obj_id__event_session: load_ae_obj_id__event_session,
load_ae_obj_li__event_session: load_ae_obj_li__event_session,
qry__event_session: qry__event_session,
search__event_session: search__event_session,
email_sign_in__event_session: email_sign_in__event_session,
db_save_ae_obj_li__event_session: db_save_ae_obj_li__event_session,
load_ae_obj_id__event_presentation: load_ae_obj_id__event_presentation,
load_ae_obj_li__event_presentation: load_ae_obj_li__event_presentation,
create_ae_obj__event_presentation: create_ae_obj__event_presentation,
db_save_ae_obj_li__event_presentation: db_save_ae_obj_li__event_presentation,
load_ae_obj_id__event_presenter: load_ae_obj_id__event_presenter,
load_ae_obj_li__event_presenter: load_ae_obj_li__event_presenter,
delete_ae_obj_id__event_presenter: delete_ae_obj_id__event_presenter,
create_ae_obj__event_presenter: create_ae_obj__event_presenter,
update_ae_obj__event_presenter: update_ae_obj__event_presenter,
search__event_presenter: search__event_presenter,
db_save_ae_obj_li__event_presenter: db_save_ae_obj_li__event_presenter,
email_sign_in__event_presenter: email_sign_in__event_presenter,
handle_load_ae_obj_id__badge: handle_load_ae_obj_id__badge,
handle_load_ae_obj_li__badge: handle_load_ae_obj_li__badge,
handle_search__event_badge: handle_search__event_badge,
handle_db_save_ae_obj_li__badge: handle_db_save_ae_obj_li__badge,
handle_load_ae_obj_id__exhibit: handle_load_ae_obj_id__exhibit,
handle_load_ae_obj_li__exhibit: handle_load_ae_obj_li__exhibit,
handle_load_ae_obj_id__exhibit_tracking: handle_load_ae_obj_id__exhibit_tracking,
handle_load_ae_obj_li__exhibit_tracking: handle_load_ae_obj_li__exhibit_tracking,
handle_create_ae_obj__exhibit_tracking: handle_create_ae_obj__exhibit_tracking,
handle_update_ae_obj__exhibit_tracking: handle_update_ae_obj__exhibit_tracking,
handle_download_export__event_exhibit_tracking: handle_download_export__event_exhibit_tracking,
handle_db_save_ae_obj_li__exhibitor: handle_db_save_ae_obj_li__exhibitor,
create_event_file_obj_from_hosted_file_async: create_event_file_obj_from_hosted_file_async,
};
export let events_func = export_obj;

547
src/lib/ae_events_stores.ts Normal file
View File

@@ -0,0 +1,547 @@
import { localStorageStore } from '@skeletonlabs/skeleton';
import { writable } from 'svelte/store';
import type { Writable } from 'svelte/store';
import type { key_val } from '$lib/ae_stores';
// Set the version for the app data. Changing this should force a notification and ask the user to clear and reload the page.
let ver = '2024-08-21_1646';
let ver_idb = '2024-08-21_1645';
/* *** BEGIN *** Initialize events_local_data_struct */
// Longer-term app data. This should be stored to *local* storage.
// Updated 2024-03-06
let events_local_data_struct: key_val = {
ver: ver,
ver_idb: ver_idb,
// Shared
name: 'Aether - Events (SvelteKit 2.x Svelte 4.x)',
title: `OSIT's Æ Events`, // - Dev SvelteKit`, // &AElig;
'ds': {},
'events_cfg_json': {},
'default__event_id': null, // OSIT Demo pjrcghqwert
'default__location_id': null,
'default__session_id': null,
// all, disabled, enabled
'qry__enabled': 'enabled',
// all, hidden, not_hidden
'qry__hidden': 'not_hidden',
'qry__limit': 20,
'qry__offset': 0,
// The show details is intended for things like meta data and additional details that are not always needed.
show_details: false,
auth__person: {}, // allow, id, name, email, passcode, etc
// The auth__entered_key (usually email or person_id) and auth__entered_passcode is found under events_sess.entered_key and events_sess.entered_passcode because it should be temporary.
// auth__entered_passcode: null,
// The auth__kv (key value pairs) is used to store the xyz IDs that the browser client can access. This is a key value list of xyz ID and created datetime stamp (or just true). These should not be more than X days old.
auth__kv: {
event: {
// 'LNDF-67-89-92': true
},
exhibit: {
// 'LNDF-67-89-92': true
},
location: {
// 'LNDF-67-89-92': true
},
session: {
// 'LNDF-67-89-92': true, false, 'read', 'write'
},
presentation: {
// 'LNDF-67-89-92': true
},
presenter: {
// 'LNDF-67-89-92': true
},
person: {
// 'LNDF-67-89-92': true
},
},
// auth__session_kv: {
// // {'LNDF-67-89-92': true}
// },
// auth__presentation_kv: {
// // {'LNDF-67-89-92': true}
// },
// auth__presenter_kv: {
// // {'LNDF-67-89-92': true}
// },
// Badge Printing
'badges': {
auto_view: true,
show_hidden: false, // These are hidden (archived) leads so the list is not as long.
show_not_enabled: false,
show_printed: false,
allow_reprint: false,
'show_element__cfg': true,
'show_element__cfg_detail': false,
'show_element__access_type': true,
'theme_mode': 'dark',
'theme_name': 'wintry',
'classes__form': 'border border-surface-200 p-4 space-y-4 rounded-container-token',
},
// Event Files - uploads for sessions, presenters, etc
'files': {
},
// Event Presentation Launcher (and native Electron app)
'launcher': {
qry_limit__sessions: 50,
qry_limit__presentations: 25,
qry_limit__presenters: 75,
qry_limit__files: 75,
show_content__disabled_files: false,
show_content__hidden_files: false,
show_content__hidden_presentations: false,
show_content__hidden_presenters: false,
show_content__hidden_sessions: false,
show_content__session_code: true,
show_content__presentation_code: true,
show_content__presenter_code: true,
time_format: 'time_us_short', // 'time_short', 'time_us_short'
slct: {
event_id: null,
event_location_id: null,
event_session_id: null,
event_presentation_id: null,
event_presenter_id: null,
event_file_id: null, // event_file_id
},
native: {
// 'local_file_cache_path': aether_cfg_data.app.local_file_cache_path,
// 'host_file_temp_path': aether_cfg_data.app.host_file_temp_path,
'host_file_config_path': 'device_configs/ae_native_app_config.default.json',
},
},
// Lead Retrievals (Exhibit)
'leads': {
show_option__paid_tab: true,
show_content__scan_alert: true, // For QR scanner bug...
show_content__scan_requirements: true,
show_content__custom_question_descriptions: true,
show_content__email_link_warning: true,
default_to_scan: true,
// For ISHLT 2024 Annual Meeting only!
default__external_registration_id: '2024_Annual Meeting',
auto_view: true, // Show the new lead after added by scan or search
auto_hide_on_sign_in: true,
show_hidden: false, // These are hidden (archived) leads so the list is not as long.
show_not_enabled: false,
refresh_interval__tracking_li: 30000, // 30 seconds
// The entered_passcode is the exhibit booths shared passcode for staff. This is used to initially access the lead retrieval service.
entered_passcode: null,
// The auth_exhibit_kv (key value pairs) is used to store the exhibit IDs that the browser client can access. This is a key value list of exhibit ID and created datetime stamp. These should not be more than X days old. The entered_passcode for events_sess.leads is what they are entering to log in.
auth_exhibit_kv: {
// {'LNDF-67-89-92': {key: 'example@oneskyit.com', updated_on: '2024-03-13T08:05:29Z}}
},
// The auth_exhibit_license_li is used to store the exhibit license(s) being used on the browser client. There can be multiple exhibit IDs, but only one license per exhibit ID for the browser client. This is used to determine who can actually access and use the lead retrieval service. This is a key value list of key (email address) and created datetime stamp. These should not be more than X days old.
// auth_exhibit_license_li: {
// // 'LNDF-67-89-92': { 'key': 'example@oneskyit.com', 'updated_on': '2024-03-13T08:05:29Z'}
// },
edit_license_li: false,
// The "tab" is a key value list of exhibit ID and tab name. This is intentionally using local storage to store the current tab for each exhibit.
// example: {'LNDF-67-89-92': 'start', 'OFLN-32-38-14': 'add_scan'}
tab: {},
},
// Presentation Management (Distributing)
'pres_mgmt': {
qry_enabled: 'enabled', // all, disabled, enabled
qry_hidden: 'not_hidden', // all, hidden, not_hidden
qry_limit__files: 75,
qry_limit__presentations: 25,
qry_limit__presenters: 75,
qry_limit__sessions: 100,
qry_max: 500, // This is the max number the limit is allowed to be set to.
qry_and__file_count: true, // Essentially it should be greater than 0
save_search_text: true,
saved_search__session: null,
// show_content__agree_text: false,
show_content__event_view: null,
show_content__launcher_link: false,
show_content__location_link: false,
show_content__location_qr: false,
show_content__presentation_description: false,
show_content__presenter_page_help: true,
// show_content__presenter_start: false,
show_content__presenter_view: null,
show_content__presenter_qr: false,
show_content__session_description: false,
show_content__session_files: false,
show_content__session_help: true,
show_content__session_presentations: false,
show_content__session_search_view: null,
show_content__session_search_help: true,
show_content__session_search_room_name: false,
show_content__session_view: null,
show_content__session_qr: false,
hide__session_poc: true,
show_content__disabled_files: false,
show_content__hidden_files: false,
show_content__hidden_presentations: false,
show_content__hidden_presenters: false,
show_content__hidden_sessions: false,
show_content__presentation_code: true,
show_content__presenter_code: true,
show_content__session_code: true,
show_menu__presenter: null,
show_menu__session: null,
show_menu__session_search: null,
show_menu__event_reports: null,
show_report__presenters_agree: false,
show_report__recent_files: false,
// time_format: 'time_us_short', // 'time_short', 'time_us_short'
disable_submit__opt_out: true,
submit_status__opt_out: null,
},
// Speakers Management (Collection)
'speakers': {
'default__session_id': null, // Assign to new presenters by default
status__submit: null, // 'saving', 'created', 'updated'
},
// other
}
// console.log(`AE Stores - App Events Local Storage Data:`, events_local_data_struct);
// This works, but does not uses local storage:
// export let ae_loc = writable(events_local_data_struct);
// This works and uses *local* storage:
export let events_loc: Writable<key_val> = localStorageStore('ae_events_loc', events_local_data_struct);
// console.log(`AE Stores - App Local Storage Data:`, get(ae_loc));
/* *** BEGIN *** Initialize events_session_data_struct */
// Temporary app data. This should be stored to session storage.
// Updated 2024-03-06
let events_session_data_struct: key_val = {
ver: ver,
ver_idb: ver_idb,
log_lvl: 1,
// Shared
'ds': {
'submit_status': null,
},
'ds_loaded': {
},
'qry__enabled': 'enabled', // all, disabled, enabled
'qry__hidden': 'not_hidden', // all, hidden, not_hidden
'qry__limit': 20,
'qry__offset': 0,
// This is intended to only be temporary.
auth__person: {},
auth__entered_key: null,
auth__entered_passcode: null,
auth__kv: {
event: {},
exhibit: {},
location: {},
session: {},
presentation: {},
presenter: {},
person: {},
},
// Badge Printing
'badges': {
'fulltext_search_qry_str': null,
'status_qry__search': null,
show_form__search: true,
show_form__search_results: true,
show_form__scan: false,
qr_scan_start: true,
qr_scan_result: null,
},
// Event Files - uploads for sessions, presenters, etc
'files': {
disable_submit__event_file_obj: null,
status__submit: null,
status__file_list: null, // processing, complete
processed_file_list: [],
},
// Event Presentation Launcher (and native Electron app)
'launcher': {
native: {
},
},
// Lead Retrievals (Exhibit)
'leads': {
example: true,
show_form__license: false,
show_form__search: false,
show_form__scan: false,
show_form__view_lead: false, // Set to event_exhibit_tracking_id
// show_form__view_lead: [],
show_confirm__add_lead: [],
submit_status__license: null, // 'saving', 'created', 'updated'
// create_status__license: null, // 'creating', 'created', 'updated'
// update_status__license: null, // 'updating', 'created', 'updated'
submit_status__search: null, // 'searching', 'complete'
// The entered_passcode is the exhibit booths shared passcode for staff. This is used to initially access the lead retrieval service.
entered_passcode: null,
tmp_license: {
'index': null,
// 'agree' : false, // The user must agree to the license agreement.
'email': '',
'full_name': '',
'passcode': '',
'session_count': 0,
'updated_on': new Date().toISOString()
},
entered_search_str: null,
lead_data_changed: null,
qr_scan_start: true,
qr_scan_result: null,
},
'stripe': {
'license_qty': 1,
'rental_qty': 0,
'rental_option': true,
'api_use': false,
'client_reference_id': null,
'publishable_key': 'pk_live_zqaWNDfak2eDHeqnRiyaJcFi',
'btn_payment_id': null,
'btn_1_license': 'buy_btn_1OvqWJ2gJkNsDuiNqMCWz5nG',
'btn_1_license_rental': 'buy_btn_1OvqVA2gJkNsDuiNhk9r8Io2',
'btn_3_license': 'buy_btn_1OvrI22gJkNsDuiNXjBg3c4Y',
'btn_3_license_rental': 'buy_btn_1OvrKa2gJkNsDuiNhSBCkNau',
'btn_6_license': 'buy_btn_1OvrWc2gJkNsDuiN7mnwvZNL',
'btn_6_license_rental': 'buy_btn_1OvrXP2gJkNsDuiNZpWZs3Uy',
'btn_10_license': 'buy_btn_1OvrPM2gJkNsDuiNRCMHfSuz',
'btn_10_license_rental': 'buy_btn_1OvrPs2gJkNsDuiN1nPkjPOM',
},
// Presentation Management (Distributing)
'pres_mgmt': {
// presenter__url_str: null,
presenter__updated_on: null,
session_updated_on: null,
location_name_qry_str: null,
fulltext_search_qry_str: null,
status_qry__search: null,
disable_submit__event_file_obj: true,
show_form__search: true,
show_form__search_results: true,
show_content__agree_text: false,
show_content__presenter_start: false,
show_report__presenters_agree: false,
show_report__recent_files: false,
show_field_edit__filename: false, // For file rename
new_upload_list: null,
files_uploading_count: null,
qry_limit__sessions: 75,
qry_limit__presentations: 25,
qry_limit__presenters: 75,
qry_limit__files: 75,
show_fields__presentation: true,
show_fields__session: true,
status_rpt: {
recent_files: null,
presenters_agree: null,
presenters_biography: null,
},
tmp_val__filename_no_ext: null, // For file rename
},
// Speakers Management (Collection)
// other
};
// console.log(`AE Stores - App Events Session Storage Data:`, events_session_data_struct);
export let events_sess = writable(events_session_data_struct);
/* *** BEGIN *** Initialize events_slct and events_trigger */
/* The slct and slct_trigger variable should not be stored in local storage. Only use session storage because browser tabs can be open to different events, badges, exhibits, etc. */
// Intended for temporary session storage.
// Updated 2024-03-06
let events_slct_obj_template: key_val = {
// Top level
'event_id': null,
'event_obj': {},
'event_obj_li': [],
// Sub-level event_
'abstract_id': null,
'abstract_obj': {},
'abstract_obj_li': [],
'badge_id': null,
'badge_obj': {},
'badge_obj_li': [],
'badge_template_id': null,
'badge_template_obj': {},
'badge_template_obj_li': [],
'device_id': null,
'device_obj': {},
'device_obj_li': [],
'exhibit_id': null,
'exhibit_obj': {},
'exhibit_obj_li': [],
// Rename these to badge_tracking_*?
'exhibit_tracking_id': null,
'exhibit_tracking_obj': {},
'exhibit_tracking_obj_li': [],
'file_id': null,
'file_obj': {},
'file_obj_li': [],
'event_file_obj': {},
'event_file_obj_li': [],
'location_id': null,
'location_obj': {},
'location_obj_li': [],
'person_id': null,
'person_obj': {},
'person_obj_li': [],
'presentation_id': null,
'presentation_obj': {},
'presentation_obj_li': [],
'event_presentation_obj': {},
'presenter_id': null,
'presenter_obj': {},
'presenter_obj_li': [],
'event_presenter_obj': {},
'session_id': null,
'session_obj': {},
'session_obj_li': [],
'event_session_obj': {},
'lq__presenter_obj': {}, // Testing passing a LiveQuery object around...
'auth__event_presenter_id': null,
'auth__event_presentation_id': null,
};
// console.log(`AE Stores - Selected Events Objects:`, events_slct_obj_template);
// This works, and uses *session* (not local) storage:
export let events_slct = writable(events_slct_obj_template);
// This works and uses *local* storage:
// export let events_slct: Writable<key_val> = localStorageStore('ae_events_slct', events_slct_obj_template);
/* *** BEGIN *** Initialize events_trigger */
// Intended for temporary session storage.
// Updated 2024-03-06
export let events_trigger: any = writable(null);
// console.log(`AE Events Stores - Events Trigger:`, events_trigger);
let tmp__events_trig: key_val = {
'event_id': null,
'event_id_li': [],
'event_location_id': null,
'event_location_id_li': [],
'event_session_id': null,
'event_session_id_li': [],
'event_presentation_id': null,
'event_presentation_id_li': [],
'event_presenter_id': null,
'event_presenter_id_li': [],
};
// console.log(`AE Stores - Events Trigger:`, events_trig);
export let events_trig: Writable<key_val> = writable(tmp__events_trig);
/* *** BEGIN *** TESTING Initialize trig_resp */
// The idea behind this is for a shared (Svelte app (within Events for now)) trigger and response. In theory this could be used to monitor multiple downloads or have a universal status area. Intended for temporary session storage.
// Updated 2024-06-25
let tmp__events_trig_kv: key_val = {};
// {
// 'example-1':
// {
// 'a-rand-id-1': true,
// 'a-rand-id-2': false,
// 'a-rand-id-3': Promise.resolve('This is a test promise.'),
// },
// 'example-2':
// {
// 'a-rand-id-4': true,
// 'a-rand-id-5': false,
// 'a-rand-id-6': Promise.resolve('This is a test promise.'),
// },
// };
export let events_trig_kv = writable(tmp__events_trig_kv);

View File

@@ -0,0 +1,14 @@
// This file is used to export all the functions that are used for Aether Events related functions.
// import {
// handle_load_ae_obj_id__note,
// handle_load_ae_obj_li__note,
// handle_db_save_ae_obj_li__note,
// } from "$lib/ae_notes__note";
let export_obj = {
// handle_load_ae_obj_id__note: handle_load_ae_obj_id__note,
};
export let notes_func = export_obj;

View File

@@ -0,0 +1,70 @@
import { localStorageStore } from '@skeletonlabs/skeleton';
import { writable } from 'svelte/store';
import type { Writable } from 'svelte/store';
import type { key_val } from '$lib/ae_stores';
/* *** BEGIN *** Initialize notes_local_data_struct */
// This is for longer term or sticky app data. This should be stored to *local* storage.
// Updated 2024-08-20
let notes_local_data_struct: key_val = {
ver: '2024-08-20_19',
// Shared
name: 'Aether - Notes (SvelteKit 2.x Svelte 4.x)',
title: `OSIT's Æ Notes`, // &AElig;
mode__edit: false,
mode__debug: false,
};
// console.log(`AE Stores - App Notes Local Storage Data:`, notes_local_data_struct);
// This works and uses *local* storage:
export let notes_loc: Writable<key_val> = localStorageStore('ae_notes_loc', notes_local_data_struct);
// console.log(`AE Stores - App Local Storage Data:`, get(ae_loc));
/* *** BEGIN *** Initialize notes_session_data_struct */
// Temporary app data. This is lost if the page is refreshed or using different tabs/windows. This should be stored to *session* storage.
// Updated 2024-08-20
let notes_session_data_struct: key_val = {
ver: '2024-08-20_19',
log_lvl: 1,
// Shared Triggers
trigger: null,
trigger__note_id: null,
// trigger__note_li: null,
};
// console.log(`AE Stores - App Notes Session Storage Data:`, notes_session_data_struct);
export let notes_sess = writable(notes_session_data_struct);
/* *** BEGIN *** Initialize notes_slct and notes_trigger */
/* The slct and slct_trigger variable should not be stored in local storage. Only use session storage because browser tabs can be open to different notes, badges, exhibits, etc. */
// Intended for temporary session storage.
// Updated 2024-08-20
let notes_slct_obj_template: key_val = {
// Top level
'note_id': null,
'note_obj': {},
'note_obj_li': [],
'lq__note_obj': {}, // Testing passing a LiveQuery object around...
};
// console.log(`AE Stores - Selected Notes Objects:`, notes_slct_obj_template);
// This works, and uses *session* (not local) storage:
export let notes_slct = writable(notes_slct_obj_template);
/* *** BEGIN *** Initialize notes_trigger */
// Intended for temporary session storage.
// Updated 2024-08-20
export let notes_trigger: any = writable(null);
// console.log(`AE Notes Stores - Notes Trigger:`, notes_trigger);

View File

@@ -0,0 +1,120 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import type { log } from 'console';
// import { liveQuery } from "dexie";
// import { db_core } from "$lib/db_core";
// let example_li = liveQuery(
// () => db_core.sponsorships.toArray()
// );
let ae_promises: key_val = {}; // Promise<any>;
// Updated 2024-03-29
async function handle_load_ae_obj_id__sponsorship_cfg(
{
api_cfg,
sponsorship_cfg_id,
try_cache=false,
log_lvl=0
}: {
api_cfg: any,
sponsorship_cfg_id: string,
try_cache: boolean,
log_lvl: number
}
) {
console.log(`*** handle_load_ae_obj_id__sponsorship_cfg() *** sponsorship_cfg_id=${sponsorship_cfg_id}`);
if (!api_cfg.account_id) {
console.log(`*ae_func* No account_id found in API config!'`);
return false;
}
let params = {};
// ae_loc.hub.sponsorships.qry_status = 'loading';
ae_promises.load__sponsorship_cfg_obj = api.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'sponsorship_cfg',
obj_id: sponsorship_cfg_id,
use_alt_table: false, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value in the API config.
params: params,
log_lvl: log_lvl
})
.then(function (sponsorship_cfg_obj_get_result) {
if (sponsorship_cfg_obj_get_result) {
if (log_lvl) {
console.log(`*ae_func* Got a result for sponsorship_cfg_id ${sponsorship_cfg_id}`);
} else if (log_lvl > 1) {
console.log(`*ae_func* Got a result for sponsorship_cfg_id ${sponsorship_cfg_id}:`, sponsorship_cfg_obj_get_result);
}
return sponsorship_cfg_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
return ae_promises.load__sponsorship_cfg_obj;
}
async function handle_download_export__sponsorship(
{
api_cfg,
account_id,
file_type='CSV', // 'CSV' or 'Excel'
return_file=true,
filename='no_filename.csv',
auto_download=false,
params={}, // key value object is expected
log_lvl=0
}: {
api_cfg: any,
account_id: string,
file_type?: string,
return_file?: boolean,
filename?: string,
auto_download?: boolean,
params?: key_val,
log_lvl?: number
}
) {
console.log('*** stores_event_api.js: get_sponsorship_export() ***');
const endpoint = `/v2/crud/sponsorship/list`;
params['for_obj_type'] = 'account';
params['for_obj_id'] = account_id;
if (file_type == 'CSV' || file_type == 'Excel') {
params['file_type'] = file_type;
}
params['return_file'] = true;
ae_promises.download__sponsorship_export_file = await api.get_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
return_blob: return_file,
filename: filename,
auto_download: auto_download,
log_lvl: log_lvl
});
console.log('ae_promises.download__sponsorship_export_file:', ae_promises.download__sponsorship_export_file);
return ae_promises.download__sponsorship_export_file;
}
let export_obj = {
handle_load_ae_obj_id__sponsorship_cfg: handle_load_ae_obj_id__sponsorship_cfg,
handle_download_export__sponsorship: handle_download_export__sponsorship,
};
export let spons_func = export_obj;

340
src/lib/ae_stores.ts Normal file
View File

@@ -0,0 +1,340 @@
import { localStorageStore } from '@skeletonlabs/skeleton';
import { writable } from 'svelte/store';
import type { Writable } from 'svelte/store';
import { PUBLIC_TESTING, PUBLIC_AE_API_PROTOCOL, PUBLIC_AE_API_SERVER, PUBLIC_AE_API_BAK_SERVER, PUBLIC_AE_API_PORT, PUBLIC_AE_API_PATH, PUBLIC_AE_API_SECRET_KEY, PUBLIC_AE_API_CRUD_SUPER_KEY, PUBLIC_AE_NO_ACCOUNT_ID, PUBLIC_AE_NO_ACCOUNT_ID_TOKEN, PUBLIC_AE_ACCOUNT_ID, PUBLIC_AE_EVENT_ID, PUBLIC_AE_SPONSORSHIP_CFG_ID } from '$env/static/public';
console.log(`AE Stores - PUBLIC_TESTING:`, PUBLIC_TESTING);
const api_base_url = `${PUBLIC_AE_API_PROTOCOL}://${PUBLIC_AE_API_SERVER}:${PUBLIC_AE_API_PORT}${PUBLIC_AE_API_PATH}`;
const api_base_url_bak = `${PUBLIC_AE_API_PROTOCOL}://${PUBLIC_AE_API_BAK_SERVER}:${PUBLIC_AE_API_PORT}${PUBLIC_AE_API_PATH}`;
const api_secret_key = PUBLIC_AE_API_SECRET_KEY;
const api_crud_super_key = PUBLIC_AE_API_CRUD_SUPER_KEY;
// const ae_account_id = PUBLIC_AE_ACCOUNT_ID;
let ae_account_id: null|string = null;
const ae_no_account_id = PUBLIC_AE_NO_ACCOUNT_ID;
const ae_no_account_id_token = PUBLIC_AE_NO_ACCOUNT_ID_TOKEN;
const ae_event_id = PUBLIC_AE_EVENT_ID;
const ae_sponsorship_cfg_id = PUBLIC_AE_SPONSORSHIP_CFG_ID;
// import { getStores, navigating, page, updated } from '$app/stores';
// import { assets, base, resolveRoute } from '$app/paths';
// console.log(page.path); // Everything after the domain name
// console.log(import.meta.env.MODE);
// console.log(import.meta.env.BASE_URL);
// Export the key_val type for use in other files.
export type key_val = {
[key: string]: any; // variable key
// name: string;
};
// export type key_val = key_val;
// import { html__not_set, classes__events_pres_mgmt_menu } from './ae_string_snippets';
import {string_snippets} from './ae_string_snippets';
export let ae_snip = string_snippets;
// export let ae_snip =
// {
// 'not_set': html__not_set,
// 'classes__events_pres_mgmt_menu': classes__events_pres_mgmt_menu
// };
// Set the version for the app data. Changing this should force a notification and ask the user to clear and reload the page.
let ver = '2024-08-21_1736';
let ver_idb = '2024-08-21_1735';
// *** BEGIN *** Longer-term app data. This should be stored to local storage.
export let ae_app_local_data_struct: key_val = {
'ver': '2024-08-16_1821',
'ver_idb': '2024-08-16_1826', // Clear if date IndexedDB version
name: 'Aether - App Hub (SvelteKit 2.x Svelte 4.x)',
theme: 'light',
iframe: false,
title: `OSIT's Æ`, // - Dev SvelteKit`, // &AElig;
debug: false, // A simple flag to know if we should show debug information.
edit_mode: false, // A simple flag to know if we should show edit mode options.
'account_id': ae_account_id, // OSIT Demo _XY7DXtc9MY
'account_code': 'not_set',
'account_name': 'Account Name Not Set',
'site_domain': null, // https://example.com, https://dev.example.com, etc.
'site_cfg_json': {
slct__event_id: null,
slct__event_badge_template_id: null,
slct__sponsorship_cfg_id: null,
header_image_path: null,
},
// The page access codes can be pulled from the data store "hub__page__access_code_li_json" per account.
// Currently configured for OSIT, ASCM, LCI
'page_access_code_li': {
// 'manager': '10240',
'administrator': '11500',
'trusted': '19111',
'public': 'public1980',
'authenticated': 'auth1980'
},
// 'manager_passcode': '10240',
// 'administrator_passcode': '11500',
// 'trusted_passcode': '19111',
// 'authenticated_passcode': 'auth2024',
'access_type': 'anonymous',
'administrator_access': false,
'trusted_access': false,
'public_access': false,
'authenticated_access': false,
'anonymous_access': true,
'user_email': null,
'qry__enabled': 'enabled', // all, disabled, enabled
'qry__hidden': 'not_hidden', // all, hidden, not_hidden
'qry__limit': 20,
'qry__offset': 0,
qr_scanner_version: 'one',
'admin': {
show_element__sql_qry: false,
show_element__sql_qry_results: false,
},
'ds': {},
'hub': {
'show_element__cfg': true,
'show_element__cfg_detail': false,
'show_element__access_type': true,
'theme_mode': 'light',
'theme_name': 'wintry', // wintry
'classes__form': 'border border-surface-200 p-4 space-y-4 rounded-container-token',
'qr': {},
},
'mod': {
'archives': {},
'events': {
'event_id': null,
show_edit__event_presenter_obj: false,
show_list__event_presenter_obj_li: true,
show_view__event_presenter_obj: false,
submit_status: null, // 'saving', 'created', 'updated'
// Badge Printing
// Lead Retrievals
// Presentation Management
// Speakers Management
'default_session_id': null, // Assign to presenters by default
// other
},
'journals': {},
'posts': {},
'sponsorships': {
'cfg_id': ae_sponsorship_cfg_id,
for_type: null,
for_id: null,
level_guest_max_li: {
0: 0,
1: 4, // CHOW 2024 - Friend
2: 8, // CHOW 2024 - Supporter
3: 8, // CHOW 2024 - Advocate
4: 8, // CHOW 2024 - Champion
5: 8, // CHOW 2024 - Presenting Partner
6: 16, // CHOW 2024 - Signature Partner
7: 16, // CHOW 2024 - Premier Partner
},
show_edit__sponsorship_obj: false,
show_list__sponsorship_obj_li: true,
show_view__sponsorship_obj: false,
show_question__accommodations: false,
submit_status: null, // 'saving', 'created', 'updated'
},
'testing': {},
},
'person': {
show_content__person_page_help: false,
},
test: true,
}
// console.log(`AE Stores - App Local Storage Data:`, ae_app_local_data_struct);
// This works, but does not uses local storage:
// export let ae_loc = writable(ae_app_local_data_struct);
// This works and uses local storage:
export let ae_loc: Writable<key_val> = localStorageStore('ae_loc', ae_app_local_data_struct);
// console.log(`AE Stores - App Local Storage Data:`, get(ae_loc));
// *** BEGIN *** Temporary app data. This should be stored to session storage.
export let ae_app_session_data_struct: key_val = {
'ver': '2024-02-27_13',
// ver_idb: ver_idb,
log_lvl: 0,
// 'name': 'Aether App Template',
// 'theme': 'light',
// 'account_id': ae_account_id,
'ds': {
'submit_status': null,
},
'ds_loaded': {
},
'hub': {
'show_xyz': null,
},
'mod': {
'archives': {},
'events': {
// Badge Printing
// Lead Retrievals
// Presentation Management
// Speakers Management
// other
},
'journals': {},
'posts': {},
'sponsorships': {
disable_submit__sponsorship_obj: false,
slct__level_num: 0,
show_question__accommodations: false,
submit_status: null, // 'saving', 'created', 'updated', 'saved'
},
'testing': {},
},
'person': {
show_report__person_li: false,
qry_limit__people: 100,
},
'download': {},
// For API download and upload progress status per file.
'api_download_kv': {},
// Example: {example_file_id: {status: 'downloading', endpoint: '/event/file/abc123/download', filename: 'example_file_name.ext', size_total: 0, size_loaded: 0, percent_completed: 0}}
'api_upload_kv': {}, // {example_temp_id: {status: 'uploading', endpoint: '/event/file/abc123/upload', filename: 'example_file_name.ext', size_total: 0, size_loaded: 0, percent_completed: 0}}
test: true,
};
// console.log(`AE Stores - App Session Storage Data:`, ae_app_session_data_struct);
export let ae_sess = writable(ae_app_session_data_struct);
// *** BEGIN *** Temporary API data. This should be stored to session storage.
export let ae_api_data_struct: key_val = {
'ver': '2024-08-11_11',
'base_url': api_base_url,
'base_url_bak': api_base_url_bak,
'api_secret_key': api_secret_key, // 'YOUR_API_SECRET_KEY',
'api_secret_key_bak': api_secret_key, // 'YOUR_API_SECRET_KEY',
'api_crud_super_key': api_crud_super_key, // 'YOUR_SUPER_KEY' 'zp5PtX4zUsI'
'headers': {},
'account_id': ae_account_id,
};
let ae_api_headers: key_val = {};
ae_api_headers['Access-Control-Allow-Origin'] = '*';
ae_api_headers['content-type'] = 'application/json';
ae_api_headers['x-aether-api-key'] = ae_api_data_struct.api_secret_key;
ae_api_headers['x-aether-api-token'] = 'fake-temp-token';
ae_api_headers['x-aether-api-expire-on'] = '';
if (ae_account_id) {
ae_api_headers['x-account-id'] = ae_account_id;
} else {
// ae_api_headers['x-account-id'] = ;
}
if (ae_no_account_id) {
ae_api_headers['x-no-account-id'] = ae_no_account_id;
}
ae_api_data_struct['headers'] = ae_api_headers;
console.log(`AE Stores - API Data:`, ae_api_data_struct);
export let ae_api = writable(ae_api_data_struct);
// *** BEGIN *** Trigger to update the slct variables and other things.
let ae_trig_template: key_val = {};
export let ae_trig = writable(ae_trig_template);
/* *** BEGIN *** Initialize slct and slct_trigger */
/* The slct and slct_trigger variable should not be stored in local storage. Only use session storage because browser tabs can be open to different accounts, events, sponsorships, etc. */
// Intended for temporary session storage.
// Updated 2024-03-15
let slct_obj_template: key_val = {
'account_id': ae_account_id,
'account_obj': {},
'event_id': null,
'event_obj': {},
'event_obj_li': [],
// 'event_exhibit_id': null,
// 'event_exhibit_obj': {},
// 'event_exhibit_obj_li': [],
'event_presentation_id': null,
'event_presentation_obj': {},
'event_presentation_obj_li': [],
'event_presenter_id': null,
'event_presenter_obj': {},
'event_presenter_obj_li': [],
'event_session_id': null,
'event_session_obj': {},
'event_session_obj_li': [],
'sponsorship_id': null,
'sponsorship_obj': {},
'sponsorship_obj_li': [],
'sponsorship_cfg_id': ae_sponsorship_cfg_id,
'sponsorship_cfg_obj': {},
'sponsorship_cfg_obj_li': [],
'post_id': null,
'post_obj': {},
'post_obj_li': [],
'post_comment_id': null,
'post_comment_obj': {},
'post_comment_obj_li': []
};
// console.log(`AE Stores - Selected Objects:`, slct_obj_template);
// This works, and uses *session* (not local) storage:
export let slct = writable(slct_obj_template);
// This works and uses *local* storage:
// export let slct: Writable<key_val> = localStorageStore('ae_slct', slct_obj_template);
/* *** BEGIN *** Initialize slct_trigger */
// Intended for temporary session storage.
// Updated 2024-02-27
export let slct_trigger: any = writable(null);
// console.log(`AE Stores - Selected Trigger:`, slct_trigger);

View File

@@ -0,0 +1,32 @@
// These are shared snippets of text, This is mostly HTML and CSS.
export let string_snippets: any = {};
string_snippets['html__not_set'] = `
<span
class="text-sm text-gray-500 bg-gray-100 p-1 rounded-md border border-gray-200"
>-- not set --
</span>
`;
string_snippets['classes__core_menu'] = 'flex flex-col items-center space-y-1 border border-blue-200 rounded-md py-1 px-2 hover:bg-blue-100';
string_snippets['classes__core_menu__button'] = 'btn btn-sm mx-1 variant-soft-tertiary text-info-300 hover:text-info-800';
string_snippets['classes__core_menu__button_highlight'] = 'btn btn-sm mx-1 variant-filled-tertiary text-info-300 hover:text-info-800';
string_snippets['classes__core_menu__button_warning'] = 'btn btn-sm mx-1 variant-soft-warning text-info-300 hover:text-info-800';
// string_snippets['classes__events_pres_mgmt_menu'] = 'flex flex-col items-center space-y-1 border border-blue-200 rounded-md py-1 px-2 hover:bg-blue-100 transition-all duration-700 hover:duration-300';
string_snippets['classes__events_pres_mgmt_menu'] = 'w-full flex flex-col items-center gap-1 border border-gray-200 rounded-md p-1 hover:bg-gray-100 transition-all duration-700 hover:duration-300';
string_snippets['classes__events_pres_mgmt_menu__button'] = 'btn btn-sm mx-1 variant-glass-secondary hover:variant-filled-secondary';
string_snippets['classes__events_pres_mgmt_menu__button_special'] = 'btn btn-sm mx-1 hover:variant-filled-primary';
// string_snippets['classes__events_pres_mgmt_menu__button'] = 'btn btn-sm mx-1 variant-soft-tertiary text-info-300 hover:text-info-800 hover:variant-filled-tertiary';
// string_snippets['classes__events_pres_mgmt_menu__button_special'] = 'btn btn-sm mx-1 variant-ghost-tertiary text-info-300 hover:text-info-800 hover:variant-filled-tertiary';
string_snippets['classes__events_pres_mgmt_menu__button_highlight'] = 'btn btn-sm mx-1 variant-filled-tertiary text-info-300 hover:text-info-800';
string_snippets['classes__events_pres_mgmt_menu__button_warning'] = 'btn btn-sm mx-1 variant-soft-warning text-info-300 hover:text-info-800';
string_snippets['classes__events_pres_mgmt_menu__button_warning_special'] = 'btn btn-sm mx-1 variant-glass-warning';
// export string_snippets;

802
src/lib/ae_utils.ts Normal file
View File

@@ -0,0 +1,802 @@
// Import external files first. Eventually this will be broken up in to smaller files.
import { process_permission_checks } from './ae_utils__perm_checks';
import { iso_datetime_formatter } from './ae_utils__datetime_format';
type key_str = {
[key: string]: string;
};
type key_val = {
[key: string]: any;
};
function format_bytes(
bytes: number,
decimals: number = 2
) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}
/* This utility function will add commas to a number. */
function number_w_commas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
// Updated 2024-08-12
function guess_file_name(filename_string: string) {
// console.log('*** guess_file_name() ***');
if (!filename_string) {
return '';
}
if (filename_string.includes('.')) {
let file_name = filename_string.substring(0, filename_string.lastIndexOf('.'));
// console.log(file_name);
return file_name;
} else {
return filename_string;
}
}
// Updated 2024-08-12
function guess_file_extension(filename_string: string) {
// console.log('*** guess_file_extension() ***');
if (!filename_string) {
return '';
}
if (!filename_string.includes('.')) {
return '';
}
let file_extension = filename_string.substring(filename_string.lastIndexOf('.') + 1, filename_string.length) || filename_string;
// console.log(file_extension);
return file_extension;
}
// Updated 2024-08-12
async function get_file_hash(file) {
return new Promise((resolve, reject) => {
let file_reader = new FileReader();
file_reader.onload = async function() {
if (file_reader.result.byteLength !== file.size) {
console.log('File was not read completely');
reject("Error reading the file");
}
const hash_buffer = await crypto.subtle.digest('SHA-256', file_reader.result);
const hash_array = Array.from(new Uint8Array(hash_buffer));
const hash_hex = hash_array.map(b => b.toString(16).padStart(2, '0')).join('');
resolve(hash_hex);
};
file_reader.readAsArrayBuffer(file);
});
}
/* This utility function looks for any form data with the prefixed name passed and returns a new object.
* This function is used heavily! Be very careful making changes!!!
* If rm_empty_id then it will remove/ignore fields matching. This helps with the API and new records/objects
* If rm_empty then it will remove/ignore fields matching. Sometimes this is needed.
* If trim_values then it will trim string values.
* If bool_tf_str then it will convert string values of true/false (case insensitive) to boolean values.
* Updated 2023-12-22
*/
export let extract_prefixed_form_data = function extract_prefixed_form_data({prefix=null, form_data={}, rm_empty_id=true, rm_empty=false, trim_values=false, bool_tf_str=false, log_lvl=0}) {
if (log_lvl) {
console.log('*** extract_prefixed_form_data() ***');
if (prefix) {
console.log(`Looking for prefixed fields: ${prefix}; Removing emptry ID fields: ${rm_empty_id}; Removing empty fields: ${rm_empty}; Trim string values: ${trim_values}; Convert true/false string values to boolean: ${bool_tf_str}`);
} else {
console.log(`No prefix set. Looking at all fields. Removing emptry ID fields: ${rm_empty_id}; Removing empty fields: ${rm_empty}; Trim string values: ${trim_values}; Convert true/false string values to boolean: ${bool_tf_str}`);
}
}
if (log_lvl > 1) {
console.log('Form Data:');
console.log(form_data);
}
// const data_obj: any = {}; // future TS
let data_obj = {};
for (let field of form_data) {
let [obj_prop_name, obj_prop_value] = field;
if (log_lvl > 1) {
console.log(`${obj_prop_name}: ${obj_prop_value} type=${typeof obj_prop_value}`);
}
// Trim string values if needed
if (trim_values && typeof obj_prop_value === 'string') {
if (log_lvl && obj_prop_value.trim() != obj_prop_value) {
console.log('Trimming string value!');
obj_prop_value = obj_prop_value.trim();
}
}
// Convert string to boolean if needed
if (bool_tf_str && typeof obj_prop_value === 'string') {
// console.log('Flag set for converting true/false string values to boolean!');
if (obj_prop_value.toLowerCase() === 'true') {
if (log_lvl) {
console.log('Converting string to boolean value: true');
}
obj_prop_value = true;
} else if (obj_prop_value.toLowerCase() === 'false') {
if (log_lvl) {
console.log('Converting string to boolean value: false');
}
obj_prop_value = false;
}
}
if (prefix && obj_prop_name.startsWith(prefix)) { // Prefix set
// if (obj_prop_name.startsWith(prefix)) {
obj_prop_name = obj_prop_name.replace(prefix, '');
if (log_lvl) {
console.log(`Checking: (${prefix})${obj_prop_name} value=${obj_prop_value}`);
}
if (rm_empty_id && obj_prop_name.endsWith('id_random') && !obj_prop_value) {
if (log_lvl) {
console.log(`Match but empty *_id_random. Ignoring/removing: ${obj_prop_name}`);
}
} else if (rm_empty && !obj_prop_value) {
if (log_lvl) {
console.log(`Match but empty. Ignoring/removing: ${obj_prop_name}`);
}
} else {
if (log_lvl) {
console.log(`Match: ${prefix})${obj_prop_name} value=${obj_prop_value}`);
}
data_obj[obj_prop_name] = obj_prop_value;
}
} else if (prefix && !obj_prop_name.startsWith(prefix)) { // Prefix set
if (log_lvl > 1) {
console.log('Did not start with prefix. Ignoring');
}
} else { // No prefix set
if (log_lvl) {
console.log(`Checking: ${obj_prop_name} value=${obj_prop_value}`);
}
if (rm_empty_id && obj_prop_name.endsWith('id_random') && !obj_prop_value) {
if (log_lvl > 1) {
console.log(`Match but empty *_id_random. Ignoring/removing: ${obj_prop_name}`);
}
} else if (rm_empty && !obj_prop_value) {
if (log_lvl > 1) {
console.log(`Match but empty. Ignoring/removing: ${obj_prop_name}`);
}
} else {
if (log_lvl > 1) {
console.log(`Match: ${obj_prop_name} value=${obj_prop_value}`);
}
data_obj[obj_prop_name] = obj_prop_value;
}
}
}
if (log_lvl > 1) {
console.log(data_obj);
}
return data_obj;
}
/* This utility function processes specific data string.
* MECARD
* OBJ = OBJ:ot:example,oi:asdf1234
* ot = Aether object type; oi = Aether object ID random
* KV = KV:"key":"value"
* JS = {"id":123,"name":"example name"}
* http or https?
* Common short keys used:
* bdg: Badge ID Random
* reg: Registration ID Random
* exid: External ID
* gn: Given First Name
* fn: Family Last Name
* em: Email Address
*/
// Updated 2022-02-11
export let process_data_string = function process_data_string(data_string: string) {
console.log('*** process_data_string() ***');
// console.log(data_string);
if (!data_string || data_string.length < 1) {
console.log('No data string found.');
return false;
}
let obj: key_val = {};
let colon_index = data_string.indexOf(':')
if (colon_index) {
let data_string_type = data_string.slice(0, colon_index);
console.log(data_string_type);
obj['qr_type'] = data_string_type;
if (data_string_type == 'MECARD') {
let mecard_str = data_string.slice(colon_index+1);
console.log(mecard_str);
obj['str'] = mecard_str;
} else if (data_string_type == 'OBJ') {
let key_value_str = data_string.slice(colon_index+1);
console.log(key_value_str);
let key_value_array = key_value_str.split(',');
// console.log(key_value_array);
let ot_colon_index = key_value_array[0].indexOf(':')
let obj_type = key_value_array[0].slice(ot_colon_index+1);
// console.log(obj_type);
let oi_colon_index = key_value_array[1].indexOf(':')
let obj_id = key_value_array[1].slice(oi_colon_index+1);
// console.log(obj_id);
obj['type'] = obj_type;
obj['id'] = obj_id;
} else if (data_string_type == 'JSON') {
let partial_json_str = data_string.slice(colon_index+1);
console.log(partial_json_str);
let json_str = `{${partial_json_str}}`;
console.log(json_str);
obj['json'] = JSON.parse(json_str);
} else if (data_string_type == 'STR') {
let str = data_string.slice(colon_index+1);
console.log(str);
obj['str'] = str;
} else if (data_string_type == 'http' || data_string_type == 'https') {
console.log(`http or https: ${data_string}`);
obj['type'] = 'url';
obj['url'] = data_string;
} else {
console.log('The unknown data string type was found. Returning the string part.')
let unknown_str = data_string.slice(colon_index+1);
console.log(unknown_str);
obj['str'] = unknown_str;
}
} else {
console.log('The data string type was not found. Returning the entire string.')
console.log(data_string);
obj['qr_type'] = 'UNKNOWN';
obj['str'] = data_string;
// return false;
}
console.log(obj);
return obj; // Returns an object
}
// This function will update the URL and send a message to the parent window (iframe).
// The name should be something like "example_id".
// Svelte specific:
// WARNING: Avoid using `history.pushState(...)` and `history.replaceState(...)` as these will conflict with SvelteKit's router. Use the `pushState` and `replaceState` imports from `$app/navigation` instead.
// Updated 2024-03-02
import { pushState, replaceState } from '$app/navigation';
function handle_url_and_message(name: string, value: null|string) {
console.log(`*** handle_url_and_message() *** name=${name} value=${value}`);
let location = window.location.href;
// console.log('location:', location);
const url = new URL(location);
// console.log('url:', url);
if (value) {
url.searchParams.set(name, value);
history.pushState({}, '', url);
// console.log('url:', url);
// pushState(url.href, {});
// pushState(url.search, {});
// replaceState(url.href, {});
let message = {name: value};
window.parent.postMessage(message, "*");
} else {
url.searchParams.delete(name);
history.pushState({}, '', url);
// console.log('url:', url);
// pushState({}, '', url.search);
// pushState(url.href, {});
// replaceState(url.href, {});
let message = {name: null};
window.parent.postMessage(message, "*");
}
// console.log('Message sent to parent (iframe):', message);
}
function create_a_element({account_id, base_url, hosted_file_id, filename=null, extension=null, text="Download", class_li='text-blue-500'}) {
return `<a href="${base_url}/hosted_file/${hosted_file_id}/download?x_no_account_id_token=${account_id}&filename=${filename}" class="${class_li}">${text}</a>`;
}
function create_img_element({account_id, base_url, hosted_file_id, filename=null, extension=null, class_li='max-w-64', style="", inc_link=false}) {
let img_html = '';
if (filename) {
img_html = `<img src="${base_url}/hosted_file/${hosted_file_id}/download?x_no_account_id_token=${account_id}&filename=${filename}" class="${class_li}" style="${style}" />`;
} else {
img_html = `<img src="${base_url}/hosted_file/${hosted_file_id}/download?x_no_account_id_token=${account_id}" class="${class_li}" style="${style}" />`;
}
if (inc_link) {
let a_html = create_a_element({account_id: account_id, base_url: base_url, hosted_file_id: hosted_file_id, filename: filename, extension: extension});
img_html = `<div class="ae_img ae_a">${img_html}${a_html}</div>`;
}
return img_html;
}
function create_video_element({account_id, base_url, hosted_file_id, filename=null, extension=null, class_li='max-w-64', inc_link=false}) {
let video_html = '';
if (filename) {
video_html = `<video src="${base_url}/hosted_file/${hosted_file_id}/download?x_no_account_id_token=${account_id}&filename=${filename}" controls class="${class_li}"></video>`;
} else {
video_html = `<video src="${base_url}/hosted_file/${hosted_file_id}/download?x_no_account_id_token=${account_id}" controls class="${class_li}"></video>`;
}
if (inc_link) {
let a_html = create_a_element({account_id: account_id, base_url: base_url, hosted_file_id: hosted_file_id, filename: filename, extension: extension});
video_html = `<div class="ae_video ae_a">${video_html}${a_html}</div>`;
}
return video_html;
}
// // Clear the quick access type
// function clear_access_type() {
// // NOTE: I think it makes since to reset this to anonymous even if logged in as an admin or similar.
// window.localStorage.setItem('access_type', 'anonymous');
// // $ae_loc.access_type = null; // 'anonymous';
// $ae_loc.access_type = 'anonymous';
// trigger = 'process_permission_check';
// show_passcode_input = false;
// // $ae_loc = $ae_loc; // Trigger Svelte just in case
// // ae_loc.set($ae_loc);
// // console.log($ae_loc);
// return true;
// }
// This function will take a long string (sentences or paraghraphs) of text and return an estimated number of words.
function count_words(text: string) {
if (!text && text.length < 1) {
return false;
}
let count = text.trim().split(/\s+/).length;
return count;
}
/* Adapted from: To Title Case © 2018 David Gouch | https://github.com/gouch/to-title-case */
// eslint-disable-next-line no-extend-native
function to_title_case (text_string) {
// console.log('*** to_title_case() ***');
let smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|the|to|v.?|vs.?|via)$/i
let alphanumericPattern = /([A-Za-z0-9\u00C0-\u00FF])/
let wordSeparators = /([ :–—-])/
return text_string.split(wordSeparators)
.map(function (current, index, array) {
if (
/* Check for small words */
current.search(smallWords) > -1 &&
/* Skip first and last word */
index !== 0 &&
index !== array.length - 1 &&
/* Ignore title end and subtitle start */
array[index - 3] !== ':' &&
array[index + 1] !== ':' &&
/* Ignore small words that start a hyphenated phrase */
(array[index + 1] !== '-' ||
(array[index - 1] === '-' && array[index + 1] === '-'))
) {
return current.toLowerCase()
}
/* Ignore intentional capitalization */
if (current.substr(1).search(/[A-Z]|\../) > -1) {
return current
}
/* Ignore URLs */
if (array[index + 1] === ':' && array[index + 2] !== '') {
return current
}
/* Capitalize the first letter */
return current.replace(alphanumericPattern, function (match) {
return match.toUpperCase()
})
})
.join('')
}
// Updated 2024-06-19
// This function behaves weirdly. It needs to be reviewed and updated.
export let shorten_string = function shorten_string(
{
string,
max_length=45,
begin_length=15,
end_length=5,
wildcard_length=3
}: {
string: undefined|string,
max_length?: number,
begin_length?: number,
end_length?: number,
wildcard_length?: number
}
) {
// console.log('*** shorten_filename() ***');
if (!string || typeof string != 'string') {
// console.log('Invalid string value passed');
// return false;
return '';
}
// NOTE: max_length is not the actual end result length. The actual max will be 45 characters.
// 20 part 1 characters, 5 part 2 characters, 20 part 3 characters
// let length = string.length;
let char_over = string.length-max_length;
let new_string = null;
let wildcards = char_over;
if (char_over > 0) {
let part1 = string.slice(0, begin_length);
let part2 = '';
if (char_over > 5) {
wildcards = 5;
} else {
}
if (wildcard_length) {
part2 = '.'.repeat(wildcard_length);
} else {
part2 = '.'.repeat(wildcards);
}
let part3 = string.slice(end_length*-1);
new_string = part1+part2+part3;
} else {
new_string = string;
}
return new_string;
}
// Updated 2024-06-19
// This function should return a shorted version of a filename if over the max length. It should always contain at least the first character of the original filename and the complete extension.
// Example 1: The Original Long File Name.pdf -> The Orig....pdf
// Example 2: The Original Long File Name.html -> The Ori....html
function shorten_filename(
{
filename,
max_length=20,
slice_end_at=15,
max_end_length=5
}: {
filename: string,
max_length?: number,
slice_end_at?: number,
max_end_length?: number
}
) {
// console.log('*** shorten_filename() ***');
if (typeof filename !== 'string' || filename.length <= max_length) {
return filename;
}
let new_filename = null;
let char_over = filename.length - max_length;
let wildcards = char_over - 4; // The number of characters over the max length
if (wildcards < 1) {
return filename; // No point in changing the filename?
}
let part_1 = filename.slice(0, slice_end_at);
if (wildcards > 3) {
wildcards = 3;
} else {
}
let part_2 = '.'.repeat(wildcards);
let part_3 = filename.slice(max_end_length*-1);
new_filename = part_1+part_2+part_3;
return new_filename;
}
// Updated 2024-6-19
function file_extension_icon(
extension: string
) {
// console.log('*** file_extension_icon() ***');
let file_icons: key_str = {
'file': 'file',
'3gp': 'file-video',
'7z': 'file-archive',
'aac': 'file-audio',
'ac3': 'file-audio',
'aif': 'file-audio',
'aiff': 'file-audio',
'avi': 'file-video',
'bmp': 'file-image',
'csv': 'file-csv',
'doc': 'file-word',
'docx': 'file-word',
'eps': 'file-image',
'flac': 'file-audio',
'gif': 'file-image',
'htm': 'file-code',
'html': 'file-code',
'jpeg': 'file-image',
'jpg': 'file-image',
'key': 'file-powerpoint',
'mkv': 'file-video',
'mov': 'file-video',
'mp3': 'file-audio',
'mp4': 'file-video',
'odp': 'file-powerpoint',
'pdf': 'file-pdf',
'png': 'file-image',
'ppt': 'file-powerpoint',
'pptx': 'file-powerpoint',
'txt': 'file-alt',
'wav': 'file-audio',
'webp': 'file-image',
'xls': 'file-excel',
'xlsx': 'file-excel',
'zip': 'file-archive'
};
if (file_icons[extension]) {
return file_icons[extension];
} else {
// return null;
return file_icons['file'];
}
}
// Updated 2023-08-18
function set_obj_prop_display_name({prop_name, obj_type=null, prefix_w_obj_type=true, prefix_all_w_obj_type=false, replace_underscores=true, title_case=true, override=null}) {
console.log('*** set_obj_prop_display_name() ***');
if (override) {
return override;
}
let known_obj_type_li = ['account', 'address', 'contact', 'event_badge', 'event_exhibit', 'event_file', 'event_location', 'event_person', 'event_presentation', 'event_presenter', 'event_registration', 'event_session', 'event', 'hosted_file', 'order_line', 'order', 'person', 'user'];
let known_obj_type_li_dict = [
{name: 'account', display: 'Account'},
{name: 'address', display: 'Address'},
{name: 'contact', display: 'Contact'},
{name: 'event_badge', display: 'Event Badge'},
{name: 'event_exhibit', display: 'Event Exhibit'},
{name: 'event_file', display: 'Event File'},
{name: 'event_location', display: 'Event Location'},
{name: 'event_person', display: 'Event Person'},
{name: 'event_presentation', display: 'Event Presentation'},
{name: 'event_presenter', display: 'Event Presenter'},
{name: 'event_registration', display: 'Event Registration'},
{name: 'event_session', display: 'Event Session'},
{name: 'event', display: 'Event'},
{name: 'hosted_file', display: 'Hosted File'},
{name: 'order_line', display: 'Order Line'},
{name: 'order', display: 'Order'},
{name: 'person', display: 'Person'},
{name: 'user', display: 'User'},
];
let prop_display_name = prop_name;
if (!prefix_w_obj_type) {
if (obj_type) {
prop_display_name = prop_name.replace(obj_type, '');
} else {
for (let i = 0; i < known_obj_type_li_dict.length; i++) {
// console.log(known_obj_type_li_dict[i]);
if (prop_name.startsWith(known_obj_type_li_dict[i].name)) {
// console.log(`Found ${known_obj_type_li_dict[i].name}`);
prop_display_name = prop_name.replace(known_obj_type_li_dict[i].name, '');
break;
}
}
// for (let i = 0; i < known_obj_type_li.length; i++) {
// // console.log(known_obj_type_li[i]);
// if (prop_name.startsWith(known_obj_type_li[i])) {
// console.log(`Found ${known_obj_type_li[i]}`);
// prop_display_name = prop_name.replace(known_obj_type_li[i], '');
// break;
// }
// }
}
} else {
if (!prefix_all_w_obj_type) {
for (let i = 0; i < known_obj_type_li.length; i++) {
// console.log(known_obj_type_li[i]);
let found_obj_type = null;
if (prop_name.startsWith(known_obj_type_li_dict[i].name)) {
// if (prop_name.startsWith(known_obj_type_li[i])) {
// console.log(`Found ${known_obj_type_li_dict[i].name}`);
found_obj_type = known_obj_type_li_dict[i].name;
if (found_obj_type == obj_type) {
prop_display_name = prop_name.replace(known_obj_type_li_dict[i].name, '');
}
break;
}
}
// if (obj_type) {
// prop_display_name = prop_name.replace(obj_type, '');
// } else {
}
}
// console.log(prop_display_name);
if (prop_display_name.search('ID')) {
}
prop_display_name = prop_display_name.replace('id_random', 'ID');
if (replace_underscores) {
prop_display_name = prop_display_name.replaceAll('_', ' ');
}
if (title_case) {
prop_display_name = to_title_case(prop_display_name);
}
// console.log(prop_display_name);
return prop_display_name;
}
function return_obj_type_path({obj_type=null, obj_type_prop_name=null}) {
console.log('*** set_obj_prop_display_name() ***');
let obj_type_path = null;
let known_obj_type_li = ['account', 'address', 'archive', 'archive_content', 'contact', 'event_badge', 'event_exhibit', 'event_file', 'event_location', 'event_person', 'event_presentation', 'event_presenter', 'event_registration', 'event_session', 'event', 'hosted_file', 'order_line', 'order', 'person', 'post', 'post_comment', 'user'];
let known_obj_type_li_dict = [
{name: 'account', display: 'Account', path: 'account'},
{name: 'archive', display: 'Archive', path: 'archive'},
{name: 'address', display: 'Address', path: 'address'},
{name: 'archive', display: 'Archive', path: 'archive'},
{name: 'archive_content', display: 'Archive Content', path: 'archive/content'},
{name: 'contact', display: 'Contact', path: 'contact'},
{name: 'data_store', display: 'Data Store', path: 'data_store'},
{name: 'event_abstract', display: 'Event Abstract', path: 'event/abstract'},
{name: 'event_badge', display: 'Event Badge', path: 'event/badge'},
{name: 'event_device', display: 'Event Device', path: 'event/device'},
{name: 'event_exhibit', display: 'Event Exhibit', path: 'event/exhibit'},
{name: 'event_file', display: 'Event File', path: 'event/file'},
{name: 'event_location', display: 'Event Location', path: 'event/location'},
{name: 'event_person', display: 'Event Person', path: 'event/person'},
{name: 'event_presentation', display: 'Event Presentation', path: 'event/'},
{name: 'event_presenter', display: 'Event Presenter', path: 'event/presenter'},
{name: 'event_registration', display: 'Event Registration', path: 'event/registration'},
{name: 'event_session', display: 'Event Session', path: 'event/session'},
{name: 'event', display: 'Event', path: 'event'},
{name: 'hosted_file', display: 'Hosted File', path: 'hosted_file'},
{name: 'journal', display: 'Journal', path: 'journal'},
{name: 'journal_entry', display: 'Journal Entry', path: 'journal/entry'},
{name: 'order_line', display: 'Order Line', path: 'order/line'},
{name: 'order', display: 'Order', path: 'order'},
{name: 'person', display: 'Person', path: 'person'},
{name: 'post', display: 'Archive', path: 'post'},
{name: 'post_comment', display: 'Archive Content', path: 'post/comment'},
{name: 'user', display: 'User', path: 'user'},
];
if (obj_type) {
// Need to loop through known for safety?
obj_type_path = obj_type_prop_name.replaceAll('_', '/');
} else if (obj_type_prop_name) {
let found_obj_type_name = null;
let found_obj_type_path = null;
for (let i = 0; i < known_obj_type_li_dict.length; i++) {
// console.log(known_obj_type_li_dict[i]);
// let guessed_obj_type = prop_name.startsWith(known_obj_type_li_dict[i]
if (obj_type_prop_name.startsWith(known_obj_type_li_dict[i].name)) {
console.log(`Found ${known_obj_type_li_dict[i].name}`);
found_obj_type_name = known_obj_type_li_dict[i].name;
found_obj_type_path = known_obj_type_li_dict[i].path;
// obj_type_path = obj_type_prop_name.replaceAll('_', '/');
obj_type_path = found_obj_type_path;
break;
}
}
} else {
console.log('Missing required parameters');
return false;
}
return obj_type_path;
}
export let ae_util = {
process_permission_checks: process_permission_checks,
iso_datetime_formatter: iso_datetime_formatter,
format_bytes: format_bytes,
number_w_commas: number_w_commas,
guess_file_name: guess_file_name,
guess_file_extension: guess_file_extension,
get_file_hash: get_file_hash,
extract_prefixed_form_data: extract_prefixed_form_data,
process_data_string: process_data_string,
handle_url_and_message: handle_url_and_message,
create_a_element: create_a_element,
create_img_element: create_img_element,
create_video_element: create_video_element,
count_words: count_words,
to_title_case: to_title_case,
shorten_string: shorten_string,
shorten_filename: shorten_filename,
file_extension_icon: file_extension_icon,
set_obj_prop_display_name: set_obj_prop_display_name,
return_obj_type_path: return_obj_type_path,
};

View File

@@ -0,0 +1,140 @@
import dayjs from 'dayjs';
export let iso_datetime_formatter = function iso_datetime_formatter(
raw_datetime: null|string|Date = null,
named_format: string = 'datetime_iso_no_seconds', // date_iso, datetime_iso_no_seconds
) {
// console.log('*** iso_datetime_formatter() ***');
// https://en.wikipedia.org/wiki/ISO_8601
// https://day.js.org/docs/en/display/format
// ISO 8601-1:2019 includes the T before the time portion
// ISO 8601-1:2019 midnight may only be referred to as "00:00", corresponding to the beginning of a calendar day
// and "24:00" is no longer allowed corresponding to the end of a day
// 60 is only used to denote an added leap second
// ISO 8601 UTC: 2021-03-04T19:04:44+00:00
// ISO 8601 UTC: 2021-03-04T19:04:44Z
// ISO 8601 UTC: 20210304T190444Z
// datetime_iso 'YYYY-MM-DD HH:mm:ss'
// datetime_iso_12 'YYYY-MM-DD hh:mm:ss A'
// datetime_iso_12_short 'YY-MM-DD hh:mm A'
// datetime_iso_tz 'YYYY-MM-DD HH:mm:ss'
// datetime_us_no_seconds 'YYYY-MM-DD hh:mm A'
// datetime_long 'dddd, MMMM D, YYYY hh:mm:ss A'
// datetime_medium 'ddd, MMM D, YYYY hh:mm:ss A'
// datetime_short 'MMM D, YY hh:mm A'
// date_iso 'YYYY-MM-DD'
// date_long 'dddd, MMMM D, YYYY'
// date_medium 'ddd, MMM D, YYYY'
// date_short 'MMM D, YY'
// time_iso 'HH:mm:ss'
// time_iso_12 'hh:mm:ss A'
// time_long 'hh:mm:ss A'
// time_medium 'h:m:s A'
// time_short 'hh:mm A'
// dayjs(raw_datetime).format('dddd, MMMM D, YYYY hh:mm:ss A');
if (!raw_datetime) {
raw_datetime = new Date(); // Get the current datetime if one was not passed.
}
let datetime_string = null;
switch (named_format) {
case 'datetime_iso':
datetime_string = dayjs(raw_datetime).format('YYYY-MM-DD HH:mm:ss');
break;
case 'datetime_iso_no_seconds':
datetime_string = dayjs(raw_datetime).format('YYYY-MM-DD HH:mm');
break;
case 'datetime_iso_12_short':
datetime_string = dayjs(raw_datetime).format('YY-MM-DD hh:mm A');
break;
case 'datetime_iso_12_short_month':
datetime_string = dayjs(raw_datetime).format('MM-DD hh:mm A');
break;
case 'datetime_us_no_seconds':
datetime_string = dayjs(raw_datetime).format('YYYY-MM-DD hh:mm A');
break;
case 'datetime_short':
datetime_string = dayjs(raw_datetime).format('MMM D, YY hh:mm A');
break;
case 'datetime_medium':
datetime_string = dayjs(raw_datetime).format('MMM D, YYYY h:mm A');
break;
case 'datetime_long':
datetime_string = dayjs(raw_datetime).format('MMMM D, YYYY hh:mm A');
break;
case 'datetime_short_month':
datetime_string = dayjs(raw_datetime).format('MMM D hh:mm A');
break;
case 'datetime_long_month':
datetime_string = dayjs(raw_datetime).format('MMMM D hh:mm A');
break;
case 'datetime_short_day':
datetime_string = dayjs(raw_datetime).format('D hh:mm A');
break;
case 'date_iso':
datetime_string = dayjs(raw_datetime).format('YYYY-MM-DD');
break;
case 'date_long_month_day':
datetime_string = dayjs(raw_datetime).format('MMMM D');
break;
case 'date_short':
datetime_string = dayjs(raw_datetime).format('MMM D, YY');
break;
case 'date_short_no_year':
datetime_string = dayjs(raw_datetime).format('MMM D');
break;
case 'date_long':
datetime_string = dayjs(raw_datetime).format('MMMM D, YYYY');
break;
case 'date_full':
datetime_string = dayjs(raw_datetime).format('dddd, MMMM D, YYYY');
break;
case 'date_full_no_year':
datetime_string = dayjs(raw_datetime).format('dddd, MMMM D');
break;
case 'time_iso':
datetime_string = dayjs(raw_datetime).format('HH:mm:ss');
break;
case 'time_long':
datetime_string = dayjs(raw_datetime).format('hh:mm:ss A');
break;
case 'time_short':
datetime_string = dayjs(raw_datetime).format('HH:mm');
break;
case 'time_short_no_leading':
datetime_string = dayjs(raw_datetime).format('H:mm');
break;
case 'time_us_short':
datetime_string = dayjs(raw_datetime).format('hh:mm A');
break;
case 'time_us_short_no_leading':
datetime_string = dayjs(raw_datetime).format('h:mm A');
break;
case 'week_long':
datetime_string = dayjs(raw_datetime).format('dddd');
break;
case 'week_medium':
datetime_string = dayjs(raw_datetime).format('ddd');
break;
case 'week_short':
datetime_string = dayjs(raw_datetime).format('dd');
break;
default:
// console.log(`The named format passed (${named_format}) did not match a common name. Trying to format with the named format value.`);
datetime_string = dayjs(raw_datetime).format(named_format);
// datetime_string = dayjs(raw_datetime).format('YYYY-MM-DD HH:mm:ss');
}
return datetime_string;
}

View File

@@ -0,0 +1,195 @@
type key_val = {
[key: string]: any;
};
// NOTE: I know there is a better more efficient way to do this, but I don't have time for that right now.
export let process_permission_checks = function process_permission_checks(access_type: string) {
// let access_checks = { 'access_type': null, 'super_check': null };
let access_checks: key_val = {};
if (access_type == 'super') {
access_checks.access_type = 'super';
access_checks.super_check = true;
access_checks.manager_check = false;
access_checks.administrator_check = false;
access_checks.support_check = false;
access_checks.assistant_check = false;
access_checks.trusted_check = false;
access_checks.verified_check = false;
access_checks.provisional_check = false;
access_checks.public_check = false;
access_checks.authenticated_check = true;
access_checks.anonymous_check = false;
access_checks.super_access = true;
access_checks.manager_access = true;
access_checks.administrator_access = true;
access_checks.support_access = true;
access_checks.assistant_access = true;
access_checks.trusted_access = true;
access_checks.verified_access = true;
access_checks.provisional_access = true;
access_checks.public_access = true;
access_checks.authenticated_access = true;
access_checks.anonymous_access = true;
} else if (access_type == 'manager') {
access_checks.access_type = 'manager';
access_checks.super_check = false;
access_checks.manager_check = true;
access_checks.administrator_check = false;
access_checks.support_check = false;
access_checks.assistant_check = false;
access_checks.trusted_check = false;
access_checks.verified_check = false;
access_checks.provisional_check = false;
access_checks.public_check = false;
access_checks.authenticated_check = true;
access_checks.anonymous_check = false;
access_checks.super_access = false;
access_checks.manager_access = true;
access_checks.administrator_access = true;
access_checks.support_access = true;
access_checks.assistant_access = true;
access_checks.trusted_access = true;
access_checks.verified_access = true;
access_checks.provisional_access = true;
access_checks.public_access = true;
access_checks.authenticated_access = true;
access_checks.anonymous_access = true;
} else if (access_type == 'administrator') {
access_checks.access_type = 'administrator';
access_checks.super_check = false;
access_checks.manager_check = false;
access_checks.administrator_check = true;
access_checks.support_check = false;
access_checks.assistant_check = false;
access_checks.trusted_check = false;
access_checks.verified_check = false;
access_checks.provisional_check = false;
access_checks.public_check = false;
access_checks.authenticated_check = false;
access_checks.anonymous_check = false;
access_checks.super_access = false;
access_checks.manager_access = false;
access_checks.administrator_access = true;
access_checks.support_access = true;
access_checks.assistant_access = true;
access_checks.trusted_access = true;
access_checks.verified_access = true;
access_checks.provisional_access = true;
access_checks.public_access = true;
access_checks.authenticated_access = true;
access_checks.anonymous_access = true;
} else if (access_type == 'trusted') {
access_checks.access_type = 'trusted';
access_checks.super_check = false;
access_checks.manager_check = false;
access_checks.administrator_check = false;
access_checks.support_check = false;
access_checks.assistant_check = false;
access_checks.trusted_check = true;
access_checks.verified_check = false;
access_checks.provisional_check = false;
access_checks.public_check = false;
access_checks.authenticated_check = true;
access_checks.anonymous_check = false;
access_checks.super_access = false;
access_checks.manager_access = false;
access_checks.administrator_access = false;
access_checks.support_access = false;
access_checks.assistant_access = false;
access_checks.trusted_access = true;
access_checks.verified_access = true;
access_checks.provisional_access = true;
access_checks.public_access = true;
access_checks.authenticated_access = true;
access_checks.anonymous_access = true;
} else if (access_type == 'public') {
access_checks.access_type = 'public';
access_checks.super_check = false;
access_checks.manager_check = false;
access_checks.administrator_check = false;
access_checks.support_check = false;
access_checks.assistant_check = false;
access_checks.trusted_check = false;
access_checks.verified_check = false;
access_checks.provisional_check = false;
access_checks.public_check = true;
access_checks.authenticated_check = false;
access_checks.anonymous_check = false;
access_checks.super_access = false;
access_checks.manager_access = false;
access_checks.administrator_access = false;
access_checks.support_access = false;
access_checks.assistant_access = false;
access_checks.trusted_access = false;
access_checks.verified_access = false;
access_checks.provisional_access = false;
access_checks.public_access = true;
access_checks.authenticated_access = true;
access_checks.anonymous_access = true;
} else if (access_type == 'authenticated') {
access_checks.access_type = 'authenticated';
access_checks.super_check = false;
access_checks.manager_check = false;
access_checks.administrator_check = false;
access_checks.support_check = false;
access_checks.assistant_check = false;
access_checks.trusted_check = false;
access_checks.verified_check = false;
access_checks.provisional_check = false;
access_checks.public_check = false;
access_checks.authenticated_check = true;
access_checks.anonymous_check = false;
access_checks.super_access = false;
access_checks.manager_access = false;
access_checks.administrator_access = false;
access_checks.support_access = false;
access_checks.assistant_access = false;
access_checks.trusted_access = false;
access_checks.verified_access = false;
access_checks.provisional_access = false;
access_checks.public_access = false;
access_checks.authenticated_access = true;
access_checks.anonymous_access = true;
} else {
access_checks.access_type = 'anonymous';
access_checks.super_check = false;
access_checks.manager_check = false;
access_checks.administrator_check = false;
access_checks.support_check = false;
access_checks.assistant_check = false;
access_checks.trusted_check = false;
access_checks.verified_check = false;
access_checks.provisional_check = false;
access_checks.public_check = false;
access_checks.authenticated_check = false;
access_checks.anonymous_check = true;
access_checks.super_access = false;
access_checks.manager_access = false;
access_checks.administrator_access = false;
access_checks.support_access = false;
access_checks.assistant_access = false;
access_checks.trusted_access = false;
access_checks.verified_access = false;
access_checks.provisional_access = false;
access_checks.public_access = false;
access_checks.authenticated_access = false;
access_checks.anonymous_access = true;
}
return access_checks;
}

903
src/lib/api.ts Normal file
View File

@@ -0,0 +1,903 @@
// Aether API Library (TS)
// This is intended to be used with the Aether API. The goal is to just import all of the core functions and re-export them as a single module. This is to make it easier to import the functions into other modules.
// This needs to be cleaned up and ideally removed the need for Axios.
import type { key_val } from '$lib/ae_stores';
import { delete_object } from './api_delete_object'; // Exported at the end of this file
import { get_object } from './api_get_object'; // Exported at the end of this file
import { patch_object } from './api_patch_object'; // Exported at the end of this file
import { post_object } from './api_post_object'; // Exported at the end of this file
import { get_ae_obj_id_crud } from '$lib/api_get__crud_obj_id';
import { get_ae_obj_li_for_obj_id_crud } from '$lib/api_get__crud_obj_li_v1';
import { get_ae_obj_li_for_obj_id_crud_v2 } from '$lib/api_get__crud_obj_li_v2';
// This new function has not been tested yet!!!
// Updated 2024-08-07
export let get_ae_obj_li_for_lu = async function get_ae_obj_li_for_lu(
{
api_cfg,
// obj_type,
for_lu_type,
// for_obj_id=null,
// use_alt_table=false,
// use_alt_base=false,
// inc={},
enabled='enabled',
hidden='not_hidden',
order_by_li=null,
limit=999999,
offset=0,
// key,
// jwt=null,
headers={},
params_json=null,
// json_obj=null,
params={},
return_meta=false,
log_lvl=1
}: {
api_cfg: any,
// obj_type: string,
for_lu_type: string,
// for_lu_id?: string,
// use_alt_table?: boolean,
// use_alt_base?: boolean,
// inc?: key_val
enabled?: string,
hidden?: string,
order_by_li?: any,
limit?: number,
offset?: number,
// key: string,
// jwt?: string,
headers?: any,
params_json?: any,
// json_obj?: any,
params?: key_val,
return_meta?: boolean,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** get_ae_obj_li_for_lu() *** for_lu_type=${for_lu_type}`);
}
let endpoint = '';
if (for_lu_type == 'country_subdivision') {
endpoint = `/crud/lu/country_subdivision/list`;
} else if (for_lu_type == 'country') {
endpoint = `/crud/lu/country/list`;
} else if (for_lu_type == 'time_zone') {
endpoint = `/crud/lu/time_zone/list`;
} else {
console.log(`Unknown object type: ${for_lu_type}`);
return false;
}
if (log_lvl) {
console.log('Endpoint:', endpoint);
}
if (order_by_li) {
headers['order_by_li'] = order_by_li;
}
let allowed_enabled_list = ['all', 'enabled', 'not_enabled']
if (allowed_enabled_list.includes(enabled) ) {
params['enabled'] = enabled;
}
let allowed_hidden_list = ['all', 'hidden', 'not_hidden'];
if (allowed_hidden_list.includes(hidden) ) {
params['hidden'] = hidden;
}
if (limit >= 0) {
params['limit'] = limit;
}
if (offset >= 0) {
params['offset'] = offset;
}
let object_li_get_promise = await api.get_object({
api_cfg: api_cfg,
endpoint: endpoint,
headers: headers,
params: params,
return_meta: return_meta,
log_lvl: log_lvl
});
if (log_lvl > 1) {
console.log(object_li_get_promise);
}
return object_li_get_promise;
}
// Updated 2023-07-24
export let create_ae_obj_crud = async function create_ae_obj_crud(
{
api_cfg,
obj_type,
field_name = null,
field_value = null,
fields = {},
key,
jwt = null,
headers = {},
params = {},
data = {},
return_obj = false,
obj_v_name = '',
return_meta = false,
log_lvl = 0
} : {
api_cfg: any,
obj_type: string,
field_name?: null|string,
field_value?: any,
fields?: key_val,
key: string,
jwt?: null|string,
headers?: key_val,
params?: key_val,
data?: key_val,
return_obj?: boolean,
obj_v_name?: string,
return_meta?: boolean,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** create_ae_obj_crud() *** obj_type=${obj_type}`);
}
data['super_key'] = key;
data['jwt'] = jwt;
// NOTE: The key and or JWT should be in the header of the DELETE, GET, PATCH, POST
// This obj_v_name is the view name to use when returning data. Do not prefix it with v_. This is checked and done automatically by the API.
// This is not currently being exposed to other areas of the code. It is only used here. For now?
if (obj_v_name) {
obj_v_name = '';
}
let endpoint = '';
if (obj_type == 'account') {
endpoint = `/crud/account`;
} else if (obj_type == 'address') {
endpoint = `/crud/address`;
} else if (obj_type == 'archive') {
endpoint = `/crud/archive`;
} else if (obj_type == 'archive_content') {
endpoint = `/crud/archive/content`;
} else if (obj_type == 'contact') {
endpoint = `/crud/contact`;
} else if (obj_type == 'data_store') {
endpoint = `/crud/data_store`;
} else if (obj_type == 'event') {
endpoint = `/crud/event`;
} else if (obj_type == 'event_abstract') {
endpoint = `/crud/event/abstract`;
} else if (obj_type == 'event_badge') {
endpoint = `/crud/event/badge`;
} else if (obj_type == 'event_device') {
endpoint = `/crud/event/device`;
} else if (obj_type == 'event_exhibit') {
endpoint = `/crud/event/exhibit`;
} else if (obj_type == 'event_exhibit_tracking') {
endpoint = `/crud/event/exhibit/tracking`;
} else if (obj_type == 'event_file') {
endpoint = `/crud/event/file`;
} else if (obj_type == 'event_location') {
endpoint = `/crud/event/location`;
} else if (obj_type == 'event_person') {
endpoint = `/crud/event/person`;
} else if (obj_type == 'event_presentation') {
endpoint = `/crud/event/presentation`;
} else if (obj_type == 'event_presenter') {
endpoint = `/crud/event/presenter`;
// obj_v_name = 'event_presenter_soft_links';
} else if (obj_type == 'event_session') {
endpoint = `/crud/event/session`;
} else if (obj_type == 'event_track') {
endpoint = `/crud/event/track`;
} else if (obj_type == 'grant') {
endpoint = `/crud/grant`;
} else if (obj_type == 'hosted_file') {
endpoint = `/crud/hosted_file`;
} else if (obj_type == 'journal') {
endpoint = `/crud/journal`;
} else if (obj_type == 'journal_entry') {
endpoint = `/crud/journal/entry`;
} else if (obj_type == 'order') {
endpoint = `/crud/order`;
} else if (obj_type == 'order_line') {
endpoint = `/crud/order/line`;
} else if (obj_type == 'page') {
endpoint = `/crud/page`;
} else if (obj_type == 'person') {
endpoint = `/crud/person`;
} else if (obj_type == 'post') {
endpoint = `/crud/post`;
} else if (obj_type == 'post_comment') {
endpoint = `/crud/post/comment`;
} else if (obj_type == 'sponsorship_cfg') {
endpoint = `/crud/sponsorship/cfg`;
} else if (obj_type == 'sponsorship') {
endpoint = `/crud/sponsorship`;
} else if (obj_type == 'site') {
endpoint = `/crud/site`;
// } else if (obj_type == 'user') {
// endpoint = `/crud/user`;
} else {
console.log(`Unknown object type: ${obj_type}`);
return false;
}
if (log_lvl) {
console.log('Endpoint:', endpoint);
}
if (return_obj) {
params['return_obj'] = true;
// Pass along the view name to use for returning data.
if (obj_v_name) {
params['obj_v_name'] = obj_v_name;
}
} else {
params['return_obj'] = false; // NOTE: This is needed because the current default on the API is to return the object.
}
if (field_name) {
data['data_list'] = {}; // Really an object/dict
data['data_list'][field_name] = field_value;
// data['data_list']['testing'] = 'asdf 1234';
} else if (fields) {
data['data_list'] = fields; // Really an object/dict
}
// NOTE: The data object may contain objects that need to be converted to JSON strings. This is done by adding "_json" to the end of the property name. This is done because the API does not support nested objects. This is a limitation of the API.
if (data['data_list']) {
if (log_lvl > 1) {
console.log('Data List:', data['data_list']);
}
for (const [key, value] of Object.entries(data['data_list'])) {
// console.log(key, value);
if (key.endsWith('_json')) {
if (log_lvl) {
console.log(`${key}: ${value}`);
}
data['data_list'][key] = JSON.stringify(value);
}
}
}
if (log_lvl) {
console.log('Data:', data);
}
// params['xxxxx run_safety_check xxxxx'] = false;
params['by_alias'] = false;
if (log_lvl) {
console.log('Params:', params);
}
let object_obj_post_promise = await post_object({api_cfg: api_cfg, endpoint: endpoint, params: params, data: data, log_lvl: log_lvl});
if (log_lvl > 1) {
console.log(object_obj_post_promise);
}
return object_obj_post_promise;
}
// Updated 2023-06-28
export let update_ae_obj_id_crud = async function update_ae_obj_id_crud(
{
api_cfg,
obj_type,
obj_id,
field_name,
field_value,
fields={},
key,
jwt=null,
headers={},
params={},
data={},
return_obj=false,
obj_v_name='',
return_meta=false,
log_lvl=0
}: {
api_cfg: any,
obj_type: string,
obj_id: string,
field_name?: string,
field_value?: any,
fields?: key_val,
key: string,
jwt?: string,
headers?: key_val,
params?: key_val,
data?: null|key_val,
return_obj?: boolean,
obj_v_name?: string,
return_meta?: boolean,
log_lvl?: number
}
) {
if (log_lvl) {
console.log('*** update_ae_obj_id_crud() ***');
}
data['super_key'] = key;
data['jwt'] = jwt;
// NOTE: The key and or JWT should be in the header of the DELETE, GET, PATCH, POST
// This obj_v_name is the view name to use when returning data. Do not prefix it with v_. This is checked and done automatically by the API.
// This is not currently being exposed to other areas of the code. It is only used here. For now?
if (obj_v_name) {
obj_v_name = '';
}
let endpoint = '';
if (obj_type == 'account') {
endpoint = `/crud/account/${obj_id}`;
} else if (obj_type == 'address') {
endpoint = `/crud/address/${obj_id}`;
} else if (obj_type == 'archive') {
endpoint = `/crud/archive/${obj_id}`;
} else if (obj_type == 'archive_content') {
endpoint = `/crud/archive/content/${obj_id}`;
} else if (obj_type == 'contact') {
endpoint = `/crud/contact/${obj_id}`;
} else if (obj_type == 'data_store') {
endpoint = `/crud/data_store/${obj_id}`;
} else if (obj_type == 'event') {
endpoint = `/crud/event/${obj_id}`;
} else if (obj_type == 'event_abstract') {
endpoint = `/crud/event/abstract/${obj_id}`;
} else if (obj_type == 'event_badge') {
endpoint = `/crud/event/badge/${obj_id}`;
} else if (obj_type == 'event_device') {
endpoint = `/crud/event/device/${obj_id}`;
} else if (obj_type == 'event_exhibit') {
endpoint = `/crud/event/exhibit/${obj_id}`;
} else if (obj_type == 'event_exhibit_tracking') {
endpoint = `/crud/event/exhibit/tracking/${obj_id}`;
} else if (obj_type == 'event_file') {
endpoint = `/crud/event/file/${obj_id}`;
} else if (obj_type == 'event_location') {
endpoint = `/crud/event/location/${obj_id}`;
} else if (obj_type == 'event_person') {
endpoint = `/crud/event/person/${obj_id}`;
} else if (obj_type == 'event_presentation') {
endpoint = `/crud/event/presentation/${obj_id}`;
} else if (obj_type == 'event_presenter') {
endpoint = `/crud/event/presenter/${obj_id}`;
// obj_v_name = 'event_presenter_soft_links';
} else if (obj_type == 'event_session') {
endpoint = `/crud/event/session/${obj_id}`;
} else if (obj_type == 'event_track') {
endpoint = `/crud/event/track/${obj_id}`;
} else if (obj_type == 'grant') {
endpoint = `/crud/grant/${obj_id}`;
} else if (obj_type == 'hosted_file') {
endpoint = `/crud/hosted_file/${obj_id}`;
} else if (obj_type == 'journal') {
endpoint = `/crud/journal/${obj_id}`;
} else if (obj_type == 'journal_entry') {
endpoint = `/crud/journal/entry/${obj_id}`;
} else if (obj_type == 'order') {
endpoint = `/crud/order/${obj_id}`;
} else if (obj_type == 'order_line') {
endpoint = `/crud/order/line/${obj_id}`;
} else if (obj_type == 'page') {
endpoint = `/crud/page/${obj_id}`;
} else if (obj_type == 'person') {
endpoint = `/crud/person/${obj_id}`;
} else if (obj_type == 'post') {
endpoint = `/crud/post/${obj_id}`;
} else if (obj_type == 'post_comment') {
endpoint = `/crud/post/comment/${obj_id}`;
} else if (obj_type == 'site') {
endpoint = `/crud/site/${obj_id}`;
} else if (obj_type == 'sponsorship_cfg') {
endpoint = `/crud/sponsorship/cfg/${obj_id}`;
} else if (obj_type == 'sponsorship') {
endpoint = `/crud/sponsorship/${obj_id}`;
// } else if (obj_type == 'user') {
// endpoint = `/crud/user/${obj_id}`;
} else {
console.log(`Unknown object type: ${obj_type}`);
return false;
}
if (log_lvl) {
console.log('Endpoint:', endpoint);
}
if (return_obj) {
params['return_obj'] = true;
// Pass along the view name to use for returning data.
if (obj_v_name) {
params['obj_v_name'] = obj_v_name;
}
} else {
params['return_obj'] = false; // NOTE: This is needed because the current default on the API is to return the object.
}
if (field_name) {
data['data_list'] = {}; // Really an object/dict
data['data_list'][field_name] = field_value;
// data['data_list']['testing'] = 'asdf 1234';
} else if (fields) {
data['data_list'] = fields; // Really an object/dict
}
// NOTE: The data object may contain objects that need to be converted to JSON strings. This is done by adding "_json" to the end of the property name. This is done because the API does not support nested objects. This is a limitation of the API.
if (data['data_list']) {
if (log_lvl > 1) {
console.log('Data List:', data['data_list']);
}
for (const [key, value] of Object.entries(data['data_list'])) {
// console.log(key, value);
if (key.endsWith('_json')) {
if (log_lvl) {
console.log(`${key}: ${value}`);
}
data['data_list'][key] = JSON.stringify(value);
}
}
}
// If the data is an object then we need to loop through the object and convert any objects to JSON strings, but only if the property name ends with "_json".
// if (Array.isArray(data)) {
// // console.log('Data is an array');
// for (let i = 0; i < data.length; i++) {
// // console.log(data[i]);
// if (typeof data[i] == 'object') {
// // console.log('Data is an object');
// for (const [key, value] of Object.entries(data[i])) {
// // console.log(key, value);
// if (key.endsWith('_json')) {
// console.log(`${key}: ${value}`);
// data[i][key] = JSON.stringify(value);
// }
// }
// }
// }
// } else if (typeof data == 'object') {
// // console.log('Data is an object');
// for (const [key, value] of Object.entries(data)) {
// // console.log(key, value);
// if (key.endsWith('_json')) {
// console.log(`${key}: ${value}`);
// data[key] = JSON.stringify(value);
// }
// }
// }
if (log_lvl) {
console.log('Data:', data);
}
// params['xxxxx run_safety_check xxxxx'] = false;
params['by_alias'] = false;
if (log_lvl) {
console.log('Params:', params);
}
let object_obj_patch_promise = await patch_object({api_cfg: api_cfg, endpoint: endpoint, params: params, data: data, log_lvl: log_lvl});
if (log_lvl > 1) {
console.log(object_obj_patch_promise);
}
return object_obj_patch_promise;
}
// Updated 2023-11-14
export let delete_ae_obj_id_crud = async function delete_ae_obj_id_crud(
{
api_cfg,
obj_type,
obj_id,
key,
jwt=null,
headers={},
params={},
data={},
method='delete', // 'delete', 'disable', 'hide'
return_meta=false,
log_lvl=0
} : {
api_cfg: any,
obj_type: string,
obj_id: string,
key: string,
jwt?: string,
headers?: any,
params?: any,
data?: any,
method?: string,
return_meta?: boolean,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** delete_ae_obj_id_crud() *** obj_type: ${obj_type} obj_id: ${obj_id}`);
}
data['super_key'] = key;
data['jwt'] = jwt;
// NOTE: The key and or JWT should be in the header of the DELETE, GET, PATCH, POST
let endpoint = '';
if (obj_type == 'account') {
endpoint = `/crud/account/${obj_id}`;
} else if (obj_type == 'address') {
endpoint = `/crud/address/${obj_id}`;
} else if (obj_type == 'archive') {
endpoint = `/crud/archive/${obj_id}`;
} else if (obj_type == 'archive_content') {
endpoint = `/crud/archive/content/${obj_id}`;
} else if (obj_type == 'contact') {
endpoint = `/crud/contact/${obj_id}`;
} else if (obj_type == 'data_store') {
endpoint = `/crud/data_store/${obj_id}`;
} else if (obj_type == 'event') {
endpoint = `/crud/event/${obj_id}`;
} else if (obj_type == 'event_abstract') {
endpoint = `/crud/event/abstract/${obj_id}`;
} else if (obj_type == 'event_badge') {
endpoint = `/crud/event/badge/${obj_id}`;
} else if (obj_type == 'event_device') {
endpoint = `/crud/event/device/${obj_id}`;
} else if (obj_type == 'event_exhibit') {
endpoint = `/crud/event/exhibit/${obj_id}`;
} else if (obj_type == 'event_exhibit_tracking') {
endpoint = `/crud/event/exhibit/tracking/${obj_id}`;
} else if (obj_type == 'event_file') {
endpoint = `/crud/event/file/${obj_id}`;
} else if (obj_type == 'event_location') {
endpoint = `/crud/event/location/${obj_id}`;
} else if (obj_type == 'event_person') {
endpoint = `/crud/event/person/${obj_id}`;
} else if (obj_type == 'event_presentation') {
endpoint = `/crud/event/presentation/${obj_id}`;
} else if (obj_type == 'event_presenter') {
endpoint = `/crud/event/presenter/${obj_id}`;
} else if (obj_type == 'event_session') {
endpoint = `/crud/event/session/${obj_id}`;
} else if (obj_type == 'event_track') {
endpoint = `/crud/event/track/${obj_id}`;
} else if (obj_type == 'grant') {
endpoint = `/crud/grant/${obj_id}`;
} else if (obj_type == 'hosted_file') {
endpoint = `/crud/hosted_file/${obj_id}`;
} else if (obj_type == 'journal') {
endpoint = `/crud/journal/${obj_id}`;
} else if (obj_type == 'journal_entry') {
endpoint = `/crud/journal/entry/${obj_id}`;
} else if (obj_type == 'order') {
endpoint = `/crud/order/${obj_id}`;
} else if (obj_type == 'order_line') {
endpoint = `/crud/order/line/${obj_id}`;
} else if (obj_type == 'page') {
endpoint = `/crud/page/${obj_id}`;
} else if (obj_type == 'person') {
endpoint = `/crud/person/${obj_id}`;
} else if (obj_type == 'post') {
endpoint = `/crud/post/${obj_id}`;
} else if (obj_type == 'post_comment') {
endpoint = `/crud/post/comment/${obj_id}`;
} else if (obj_type == 'site') {
endpoint = `/crud/site/${obj_id}`;
} else if (obj_type == 'sponsorship_cfg') {
endpoint = `/crud/sponsorship/cfg/${obj_id}`;
} else if (obj_type == 'sponsorship') {
endpoint = `/crud/sponsorship/${obj_id}`;
// } else if (obj_type == 'user') {
// endpoint = `/crud/user/${obj_id}`;
} else {
console.log(`Unknown object type: ${obj_type}`);
return false;
}
if (log_lvl) {
console.log('Endpoint:', endpoint);
}
if (method) { // NOTE: method options: 'delete', 'disable', 'hide'
params['method'] = method;
}
if (log_lvl) {
console.log('Params:', params);
}
let object_obj_delete_promise = await delete_object({api_cfg: api_cfg, endpoint: endpoint, params: params, data: data, log_lvl: log_lvl});
if (log_lvl > 1) {
console.log(object_obj_delete_promise);
}
return object_obj_delete_promise;
}
/* BEGIN: Hosted File Related */
// Updated 2023-08-17
export let download_hosted_file = async function download_hosted_file(
{
api_cfg,
hosted_file_id,
return_file=true,
filename,
auto_download=false,
params={},
log_lvl=0
} : {
api_cfg: any,
hosted_file_id: string,
return_file?: boolean,
filename?: string,
auto_download?: boolean,
params?: key_val,
log_lvl?: number
}
) {
console.log('*** stores_hosted_api.js: download_hosted_file() ***');
let task_id = hosted_file_id;
const endpoint = `/hosted_file/${hosted_file_id}/download`;
if (filename) {
params['filename'] = filename;
}
params['return_file'] = true;
let hosted_file_download_get_promise = await api.get_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
return_blob: true,
filename: filename,
auto_download: auto_download,
task_id: task_id,
log_lvl: log_lvl
});
// console.log(hosted_file_download_get_promise);
return hosted_file_download_get_promise;
}
// Updated 2023-12-15
export let delete_hosted_file = async function delete_hosted_file(
{
api_cfg,
hosted_file_id,
link_to_type,
link_to_id,
rm_orphan=false,
params={},
data={},
log_lvl=1
} : {
api_cfg: any,
hosted_file_id: string,
link_to_type?: string,
link_to_id?: string,
rm_orphan?: boolean,
params?: key_val,
data?: key_val,
log_lvl?: number
}
) {
console.log('*** stores_hosted_api.js: delete_hosted_file() ***');
const endpoint = `/hosted_file/${hosted_file_id}`;
if (link_to_type) {
params['link_to_type'] = link_to_type;
}
if (link_to_id) {
params['link_to_id'] = link_to_id;
}
if (rm_orphan) {
params['rm_orphan'] = rm_orphan;
}
let hosted_file_obj_delete_promise = await api.delete_object({api_cfg: api_cfg, endpoint: endpoint, params: params, data: data, log_lvl: log_lvl});
// console.log(hosted_file_obj_delete_promise);
return hosted_file_obj_delete_promise;
}
/* END: Hosted File Related */
/* BEGIN: Data Store Related */
// Updated 2023-06-29
export let get_data_store_obj_w_code = async function get_data_store_obj_w_code({
api_cfg,
data_store_code,
data_type='text',
headers={},
params={},
timeout=25000,
log_lvl=0
} : {
api_cfg: any,
data_store_code: string,
data_type?: string,
headers?: key_val,
params?: key_val,
timeout?: number,
log_lvl?: number
}
) {
if (log_lvl) {
console.log('*** get_data_store_obj_w_code() ***');
}
// let get_item_result = window.localStorage.getItem(code);
const endpoint = `/data_store/code/${data_store_code}`;
let data_store_obj_get_promise = await api.get_object({api_cfg: api_cfg, endpoint: endpoint, headers: headers, params: params, timeout: timeout, log_lvl: log_lvl});
if (data_store_obj_get_promise === false) {
console.log('Data Store - RUN AGAIN WITH BACKUP');
let original_api_base_url = api_cfg['base_url'];
let temp_api = api_cfg;
temp_api['base_url'] = temp_api['base_url_bak']
data_store_obj_get_promise = await api.get_object({api_cfg: temp_api, endpoint: endpoint, headers: headers, params: params, timeout: timeout, log_lvl: log_lvl});
temp_api['base_url'] = original_api_base_url;
}
let data_store_obj = data_store_obj_get_promise;
if (data_type == 'text') {
// console.log(data_store_obj.text);
// window.localStorage.setItem(data_store_code, data_store_obj.text);
// localStorage.setItem(data_store_code, data_store_obj.text);
} else if (data_type == 'json') {
// console.log(data_store_obj.json);
// window.localStorage.setItem(data_store_code, JSON.stringify(data_store_obj.json));
// localStorage.setItem(data_store_code, JSON.stringify(data_store_obj.json));
}
if (log_lvl > 1) {
console.log('Response Data:', data_store_obj);
}
return data_store_obj;
}
/* END: Data Store Related */
/* BEGIN: Utility: Email Related */
// Updated 2023-06-29
export let send_email = async function send_email(
{
api_cfg,
from_email,
from_name='',
to_email,
to_name='',
cc_email=null,
cc_name=null,
bcc_email=null,
bcc_name=null,
subject,
body_html,
body_text=null,
headers={},
params={},
data={},
return_obj=false,
return_meta=false,
log_lvl=0
} : {
api_cfg: any,
from_email: string,
from_name?: string,
to_email: string,
to_name?: string,
cc_email?: string,
cc_name?: string,
bcc_email?: string,
bcc_name?: string,
subject: string,
body_html: string,
body_text?: string,
headers?: key_val,
params?: key_val,
data?: key_val,
return_obj?: boolean,
return_meta?: boolean,
log_lvl?: number
}
) {
console.log('*** send_email() ***');
let endpoint = `/util/email/send`;
data['from_email'] = from_email; // Required
data['from_name'] = from_name;
data['to_email'] = to_email; // Required
data['to_name'] = to_name;
data['cc_email'] = cc_email;
data['cc_name'] = cc_name;
data['bcc_email'] = bcc_email;
data['bcc_name'] = bcc_name;
data['subject'] = subject;
if (log_lvl) {
console.log('Data:', data);
}
data['body_html'] = body_html;
data['body_text'] = body_text;
if (return_obj) {
params['return_obj'] = true;
}
let send_email_post_promise = await api.post_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
data: data,
return_meta: return_meta,
log_lvl: log_lvl
});
if (log_lvl > 1) {
console.log('Response Data:', send_email_post_promise);
}
if (return_obj) {
return send_email_post_promise;
} else {
return send_email_post_promise.event_abstract_id_random;
}
}
/* END: Utility: Email Related */
let obj = {
delete_object: delete_object,
get_object: get_object,
patch_object: patch_object,
post_object: post_object,
get_ae_obj_id_crud: get_ae_obj_id_crud,
get_ae_obj_li_for_obj_id_crud: get_ae_obj_li_for_obj_id_crud,
get_ae_obj_li_for_obj_id_crud_v2: get_ae_obj_li_for_obj_id_crud_v2,
create_ae_obj_crud: create_ae_obj_crud,
update_ae_obj_id_crud: update_ae_obj_id_crud,
delete_ae_obj_id_crud: delete_ae_obj_id_crud,
download_hosted_file: download_hosted_file,
delete_hosted_file: delete_hosted_file,
get_data_store_obj_w_code: get_data_store_obj_w_code,
send_email: send_email,
}
export let api = obj;
// module.exports = api;

View File

@@ -0,0 +1,63 @@
import axios from 'axios';
// Updated 2024-05-23
export let delete_object = async function delete_object(
{
api_cfg=null,
endpoint='',
params={},
data={},
return_meta=false,
log_lvl=0
}: {
api_cfg: any,
endpoint: string,
params?: any,
data?: any,
return_meta?: boolean,
log_lvl?: number
}
) {
console.log('*** delete_object() ***');
if (log_lvl) {
// console.log(api_cfg);
console.log(endpoint);
console.log(params);
if (log_lvl > 1) {
console.log('Data:', data);
console.log(typeof data);
}
// console.log(return_meta);
// console.log(as_list);
}
// https://stackoverflow.com/questions/51069552/axios-delete-request-with-body-and-headers
let axios_api = axios.create({
baseURL: api_cfg['base_url'],
// timeout: 2000,
/* other custom settings */
});
axios_api.defaults.headers = api_cfg['headers'];
//OLD: axios_api.delete(endpoint, { 'data': data })
let response_data = await axios_api.delete(endpoint, { params: params, 'data': data })
.then(function (response) {
console.log(response.data);
return response.data;
})
.catch(function (error) {
if (error.response && error.response.status === 404) {
return null; // Returning null since there were no results
}
console.log(error);
return false; // Returning false since something may have gone wrong. Also more in line with what the API returns.
// return error;
});
if (log_lvl > 1) {
console.log(response_data);
}
return response_data;
}

View File

@@ -0,0 +1,172 @@
import type { key_val } from '$lib/ae_stores';
import { get_object } from './api_get_object';
// Updated 2023-12-01
export async function get_ae_obj_id_crud(
{
api_cfg,
no_account_id=false,
obj_type,
obj_id,
use_alt_table=false,
use_alt_base=false,
inc={},
enabled='enabled',
hidden='not_hidden',
limit=999999,
offset=0,
data={},
// key,
// jwt=null,
headers={},
params={},
timeout=25000,
return_meta=false,
log_lvl=0
}: {
api_cfg: any,
no_account_id?: boolean,
obj_type: string,
obj_id: string,
use_alt_table?: boolean,
use_alt_base?: boolean,
inc?: any,
enabled?: string,
hidden?: string,
limit?: number,
offset?: number,
data?: any,
// key: string,
// jwt?: string,
headers?: any,
params?: key_val,
timeout?: number,
return_meta?: boolean,
log_lvl?: number
}
) {
if (log_lvl) {
console.log('*** get_ae_obj_id_crud() ***');
}
// data = {};
// data['super_key'] = key;
// data['jwt'] = jwt;
// NOTE: The key and or JWT should be in the header of the DELETE, GET, PATCH, POST
let endpoint = '';
if (obj_type == 'account') {
endpoint = `/crud/account/${obj_id}`;
} else if (obj_type == 'address') {
endpoint = `/crud/address/${obj_id}`;
} else if (obj_type == 'archive') {
endpoint = `/crud/archive/${obj_id}`;
} else if (obj_type == 'archive_content') {
endpoint = `/crud/archive/content/${obj_id}`;
} else if (obj_type == 'contact') {
endpoint = `/crud/contact/${obj_id}`;
} else if (obj_type == 'data_store') {
endpoint = `/crud/data_store/${obj_id}`;
} else if (obj_type == 'event') {
endpoint = `/crud/event/${obj_id}`;
} else if (obj_type == 'event_abstract') {
endpoint = `/crud/event/abstract/${obj_id}`;
} else if (obj_type == 'event_badge') {
endpoint = `/crud/event/badge/${obj_id}`;
} else if (obj_type == 'event_device') {
endpoint = `/crud/event/device/${obj_id}`;
} else if (obj_type == 'event_exhibit') {
endpoint = `/crud/event/exhibit/${obj_id}`;
} else if (obj_type == 'event_exhibit_tracking') {
endpoint = `/crud/event/exhibit/tracking/${obj_id}`;
} else if (obj_type == 'event_file') {
endpoint = `/crud/event/file/${obj_id}`;
} else if (obj_type == 'event_location') {
endpoint = `/crud/event/location/${obj_id}`;
} else if (obj_type == 'event_person') {
endpoint = `/crud/event/person/${obj_id}`;
} else if (obj_type == 'event_presentation') {
endpoint = `/crud/event/presentation/${obj_id}`;
} else if (obj_type == 'event_presenter') {
endpoint = `/crud/event/presenter/${obj_id}`;
} else if (obj_type == 'event_session') {
endpoint = `/crud/event/session/${obj_id}`;
} else if (obj_type == 'event_track') {
endpoint = `/crud/event/track/${obj_id}`;
} else if (obj_type == 'grant') {
endpoint = `/crud/grant/${obj_id}`;
} else if (obj_type == 'hosted_file') {
endpoint = `/crud/hosted_file/${obj_id}`;
} else if (obj_type == 'journal') {
endpoint = `/crud/journal/${obj_id}`;
} else if (obj_type == 'journal_entry') {
endpoint = `/crud/journal/entry/${obj_id}`;
} else if (obj_type == 'order') {
endpoint = `/crud/order/${obj_id}`;
} else if (obj_type == 'order_line') {
endpoint = `/crud/order/line/${obj_id}`;
} else if (obj_type == 'page') {
endpoint = `/crud/page/${obj_id}`;
} else if (obj_type == 'person') {
endpoint = `/crud/person/${obj_id}`;
} else if (obj_type == 'post') {
endpoint = `/crud/post/${obj_id}`;
} else if (obj_type == 'post_comment') {
endpoint = `/crud/post/comment/${obj_id}`;
} else if (obj_type == 'site') {
endpoint = `/crud/site/${obj_id}`;
} else if (obj_type == 'site_domain') {
endpoint = `/crud/site/domain/${obj_id}`;
} else if (obj_type == 'sponsorship_cfg') {
endpoint = `/crud/sponsorship/cfg/${obj_id}`;
} else if (obj_type == 'sponsorship') {
endpoint = `/crud/sponsorship/${obj_id}`;
// } else if (obj_type == 'user') {
// endpoint = `/crud/user/${obj_id}`;
} else {
console.log(`Unknown object type: ${obj_type}`);
return false;
}
if (log_lvl) {
console.log('Endpoint:', endpoint);
}
params['use_alt_table'] = use_alt_table;
params['use_alt_base'] = use_alt_base;
if (log_lvl) {
console.log('Params:', params);
}
if (no_account_id) {
headers['x-no-account-id'] = 'Nothing to See Here';
delete headers['x-account-id'];
delete api_cfg['headers']['x-account-id'];
// headers['x-account-id'] = null;
// headers['x-account-id'] = '_XY7DXtc9Mxx';
// params['x_no_account_id_token'] = 'Nothing to See Here';
// Remove the x-account-id header
// if (headers['x-account-id']) {
// delete headers['x-account-id'];
// }
// headers['x-account-id'] = null;
// headers['x-no-account-id-token'] = 'Nothing to See Here'; // get_object() will fix the underscores to dashes
}
let object_obj_get_promise = await get_object({
api_cfg: api_cfg,
endpoint: endpoint,
headers: headers,
params: params,
timeout: timeout,
log_lvl: log_lvl
});
if (log_lvl > 1) {
console.log(object_obj_get_promise);
}
return object_obj_get_promise;
}

View File

@@ -0,0 +1,229 @@
import type { key_val } from '$lib/ae_stores';
import { get_object } from './api_get_object';
// The lookup "obj_type" should broken out into a separate function. - 2024-08-07
// Updated 2023-11-15
export async function get_ae_obj_li_for_obj_id_crud(
{
api_cfg,
obj_type,
for_obj_type,
for_obj_id, // NOTE: Changed 2023-12-06 to no longer required
use_alt_table=false,
use_alt_base=false,
inc={},
enabled='enabled',
hidden='not_hidden',
order_by_li=null,
limit=999999,
offset=0,
// key,
// jwt=null,
headers={},
params_json=null, // NOTE: This is a JSON object that needs to be safely converted to a string for the params. This is used for the API endpoint. Example: { "fulltext_search": { "default_qry_str": "Search string for default", "address_default_qry_str": "Search string for address", "contact_1_default_qry_str": "Search string for contact_1" } }
// json_obj=null, // NOTE: This is a JSON object that needs to be safely converted to a string for the params. This is used for the search endpoint.
params={},
return_meta=false,
log_lvl=1
}: {
api_cfg: any,
obj_type: string,
for_obj_type: string,
for_obj_id?: string,
use_alt_table?: boolean,
use_alt_base?: boolean,
inc?: key_val
enabled?: string,
hidden?: string,
order_by_li?: any,
limit?: number,
offset?: number,
// key: string,
// jwt?: string,
headers?: any,
params_json?: any,
// json_obj?: any,
params?: key_val,
return_meta?: boolean,
log_lvl?: number
}
) {
if (log_lvl) {
console.log('*** get_ae_obj_li_for_obj_id_crud() ***');
}
// data = {};
// data['super_key'] = key;
// data['jwt'] = jwt;
// NOTE: The key and or JWT should be in the header of the DELETE, GET, PATCH, POST
// const endpoint = `/crud/${obj_type}/list`;
let endpoint = '';
if (obj_type == 'account') {
endpoint = `/crud/account/list`;
} else if (obj_type == 'address') {
endpoint = `/crud/address/list`;
} else if (obj_type == 'archive') {
endpoint = `/crud/archive/list`;
} else if (obj_type == 'archive_content') {
endpoint = `/crud/archive/content/list`;
} else if (obj_type == 'contact') {
endpoint = `/crud/contact/list`;
} else if (obj_type == 'data_store') {
endpoint = `/crud/data_store/list`;
} else if (obj_type == 'event') {
endpoint = `/crud/event/list`;
} else if (obj_type == 'event_abstract') {
endpoint = `/crud/event/abstract/list`;
} else if (obj_type == 'event_badge') {
endpoint = `/crud/event/badge/list`;
} else if (obj_type == 'event_device') {
endpoint = `/crud/event/device/list`;
} else if (obj_type == 'event_exhibit') {
endpoint = `/crud/event/exhibit/list`;
} else if (obj_type == 'event_exhibit_tracking') {
endpoint = `/crud/event/exhibit/tracking/list`;
} else if (obj_type == 'event_file') {
endpoint = `/crud/event/file/list`;
} else if (obj_type == 'event_location') {
endpoint = `/crud/event/location/list`;
} else if (obj_type == 'event_person') {
endpoint = `/crud/event/person/list`;
} else if (obj_type == 'event_presentation') {
endpoint = `/crud/event/presentation/list`;
} else if (obj_type == 'event_presenter') {
endpoint = `/crud/event/presenter/list`;
} else if (obj_type == 'event_session') {
endpoint = `/crud/event/session/list`;
} else if (obj_type == 'event_track') {
endpoint = `/crud/event/track/list`;
} else if (obj_type == 'grant') {
endpoint = `/crud/grant/list`;
} else if (obj_type == 'hosted_file') {
endpoint = `/crud/hosted_file/list`;
} else if (obj_type == 'journal') {
endpoint = `/crud/journal/list`;
} else if (obj_type == 'journal_entry') {
endpoint = `/crud/journal/entry/list`;
} else if (obj_type == 'order') {
endpoint = `/crud/order/list`;
} else if (obj_type == 'order_line') {
endpoint = `/crud/order/line/list`;
} else if (obj_type == 'page') {
endpoint = `/crud/page/list`;
} else if (obj_type == 'person') {
endpoint = `/crud/person/list`;
} else if (obj_type == 'post') {
endpoint = `/crud/post/list`;
} else if (obj_type == 'post_comment') {
endpoint = `/crud/post/comment/list`;
} else if (obj_type == 'site') {
endpoint = `/crud/site/list`;
} else if (obj_type == 'sponsorship_cfg') {
endpoint = `/crud/sponsorship/cfg/list`;
} else if (obj_type == 'sponsorship') {
endpoint = `/crud/sponsorship/list`;
// } else if (obj_type == 'user') {
// endpoint = `/crud/user/list`;
// } else if (obj_type == 'lu' && for_obj_type == 'country_subdivision') {
// endpoint = `/crud/lu/country_subdivision/list`;
// for_obj_type = null;
// } else if (obj_type == 'lu' && for_obj_type == 'country') {
// endpoint = `/crud/lu/country/list`;
// for_obj_type = null;
// } else if (obj_type == 'lu' && for_obj_type == 'time_zone') {
// endpoint = `/crud/lu/time_zone/list`;
// for_obj_type = null;
} else {
console.log(`Unknown object type: ${obj_type}`);
return false;
}
if (log_lvl) {
console.log('Endpoint:', endpoint);
}
if (for_obj_type) {
params['for_obj_type'] = for_obj_type;
}
if (for_obj_id) {
params['for_obj_id'] = for_obj_id;
}
params['use_alt_table'] = use_alt_table;
params['use_alt_base'] = use_alt_base;
/* Need to deal with inc params here */
let allowed_enabled_list = ['all', 'enabled', 'not_enabled']
if (allowed_enabled_list.includes(enabled) ) {
params['enabled'] = enabled;
}
let allowed_hidden_list = ['all', 'hidden', 'not_hidden'];
if (allowed_hidden_list.includes(hidden) ) {
params['hidden'] = hidden;
}
// NOTE: The order_by_li variable is in the "headers" because if is a the URL GET params do not handle multiple values very well. Maybe base64 encore in the future or something? Reminder that GET requests should not have a body (no JSON).
// NOTE: The order_by_li should be a key value pair of the property/DB field to sort and how to sort (ASC or DESC)
if (order_by_li) {
if (log_lvl) {
console.log('Order By:', order_by_li);
}
headers['order_by_li'] = order_by_li;
}
if (limit >= 0) {
params['limit'] = limit;
}
if (offset >= 0) {
params['offset'] = offset;
}
if (params_json) {
// NOTE: This is a JSON object that needs to be safely converted to a string for the params. This is used for the search endpoint.
// Max characters for a GET request is 2083. This is a limitation of the browser (Microsoft IE and Edge).
if (log_lvl) {
console.log('JSON Object:', params_json);
console.log(JSON.stringify(params_json));
}
// NOTE: "jp" stands for "JSON Params"
params['jp'] = encodeURIComponent(JSON.stringify(params_json));
if (params['jp'].length > 2083) {
console.log(`The JSON object is too large to be used as a GET parameter. The overall max URL length is 2083 characters. Please use the POST endpoint instead. Length = ${params['jp'].length} [THIS DOES NOT EXIST YET]`);
return false;
}
}
// if (json_obj) {
// // NOTE: This is a JSON object that needs to be safely converted to a string for the params. This is used for the search endpoint.
// // Max characters for a GET request is 2083. This is a limitation of the browser (Microsoft IE and Edge).
// console.log('JSON Object:', json_obj);
// params['json_str'] = encodeURIComponent(JSON.stringify(json_obj));
// if (params['json_str'].length > 2083) {
// console.log(`The JSON object is too large to be used as a GET parameter. The overall max URL length is 2083 characters. Please use the POST endpoint instead. Length = ${params['json_str'].length} [THIS DOES NOT EXIST YET]`);
// return false;
// }
// }
if (log_lvl) {
console.log('Params:', params);
}
let object_li_get_promise = await get_object({
api_cfg: api_cfg,
endpoint: endpoint,
headers: headers,
params: params,
return_meta: return_meta,
log_lvl: log_lvl
});
if (log_lvl > 1) {
console.log(object_li_get_promise);
}
return object_li_get_promise;
}

View File

@@ -0,0 +1,236 @@
import type { key_val } from '$lib/ae_stores';
import { get_object } from './api_get_object';
// The lookup "obj_type" should broken out into a separate function. - 2024-08-07
// Updated 2023-11-15
export async function get_ae_obj_li_for_obj_id_crud_v2(
{
api_cfg,
obj_type,
for_obj_type,
for_obj_id, // NOTE: Changed 2023-12-06 to no longer required
use_alt_tbl=false,
use_alt_mdl=false,
use_alt_exp=false,
inc={},
enabled='enabled',
hidden='not_hidden',
order_by_li=null,
limit=999999,
offset=0,
// key,
// jwt=null,
headers={},
params_json=null, // NOTE: This is a JSON object that needs to be safely converted to a string for the params. This is used for the API endpoint. Example: { "fulltext_search": { "default_qry_str": "Search string for default", "address_default_qry_str": "Search string for address", "contact_1_default_qry_str": "Search string for contact_1" } }
// json_obj=null, // NOTE: This is a JSON object that needs to be safely converted to a string for the params. This is used for the search endpoint.
params={},
return_meta=false,
log_lvl=1
}: {
api_cfg: any,
obj_type: string,
for_obj_type: string,
for_obj_id?: string,
use_alt_tbl?: boolean|string,
use_alt_mdl?: boolean|string,
use_alt_exp?: boolean|string,
inc?: key_val
enabled?: string,
hidden?: string,
order_by_li?: any,
limit?: number,
offset?: number,
// key: string,
// jwt?: string,
headers?: any,
params_json?: any,
// json_obj?: any,
params?: key_val,
return_meta?: boolean,
log_lvl?: number
}
) {
if (log_lvl) {
console.log('*** get_ae_obj_li_for_obj_id_crud() ***');
}
// data = {};
// data['super_key'] = key;
// data['jwt'] = jwt;
// NOTE: The key and or JWT should be in the header of the DELETE, GET, PATCH, POST
// const endpoint = `/crud/${obj_type}/list`;
let endpoint = '';
if (obj_type == 'account') {
endpoint = `/crud/account/list`;
} else if (obj_type == 'address') {
endpoint = `/crud/address/list`;
} else if (obj_type == 'archive') {
endpoint = `/crud/archive/list`;
} else if (obj_type == 'archive_content') {
endpoint = `/crud/archive/content/list`;
} else if (obj_type == 'contact') {
endpoint = `/crud/contact/list`;
} else if (obj_type == 'data_store') {
endpoint = `/crud/data_store/list`;
} else if (obj_type == 'event') {
endpoint = `/crud/event/list`;
} else if (obj_type == 'event_abstract') {
endpoint = `/crud/event/abstract/list`;
} else if (obj_type == 'event_badge') {
endpoint = `/crud/event/badge/list`;
} else if (obj_type == 'event_device') {
endpoint = `/crud/event/device/list`;
} else if (obj_type == 'event_exhibit') {
endpoint = `/crud/event/exhibit/list`;
} else if (obj_type == 'event_exhibit_tracking') {
endpoint = `/crud/event/exhibit/tracking/list`;
} else if (obj_type == 'event_file') {
endpoint = `/crud/event/file/list`;
} else if (obj_type == 'event_location') {
endpoint = `/crud/event/location/list`;
} else if (obj_type == 'event_person') {
endpoint = `/crud/event/person/list`;
} else if (obj_type == 'event_presentation') {
endpoint = `/crud/event/presentation/list`;
} else if (obj_type == 'event_presenter') {
endpoint = `/crud/event/presenter/list`;
} else if (obj_type == 'event_session') {
endpoint = `/crud/event/session/list`;
} else if (obj_type == 'event_track') {
endpoint = `/crud/event/track/list`;
} else if (obj_type == 'grant') {
endpoint = `/crud/grant/list`;
} else if (obj_type == 'hosted_file') {
endpoint = `/crud/hosted_file/list`;
} else if (obj_type == 'journal') {
endpoint = `/crud/journal/list`;
} else if (obj_type == 'journal_entry') {
endpoint = `/crud/journal/entry/list`;
} else if (obj_type == 'order') {
endpoint = `/crud/order/list`;
} else if (obj_type == 'order_line') {
endpoint = `/crud/order/line/list`;
} else if (obj_type == 'page') {
endpoint = `/crud/page/list`;
} else if (obj_type == 'person') {
endpoint = `/crud/person/list`;
} else if (obj_type == 'post') {
endpoint = `/crud/post/list`;
} else if (obj_type == 'post_comment') {
endpoint = `/crud/post/comment/list`;
} else if (obj_type == 'site') {
endpoint = `/crud/site/list`;
} else if (obj_type == 'sponsorship_cfg') {
endpoint = `/crud/sponsorship/cfg/list`;
} else if (obj_type == 'sponsorship') {
endpoint = `/crud/sponsorship/list`;
// } else if (obj_type == 'user') {
// endpoint = `/crud/user/list`;
// } else if (obj_type == 'lu' && for_obj_type == 'country_subdivision') {
// endpoint = `/crud/lu/country_subdivision/list`;
// for_obj_type = null;
// } else if (obj_type == 'lu' && for_obj_type == 'country') {
// endpoint = `/crud/lu/country/list`;
// for_obj_type = null;
// } else if (obj_type == 'lu' && for_obj_type == 'time_zone') {
// endpoint = `/crud/lu/time_zone/list`;
// for_obj_type = null;
} else {
console.log(`Unknown object type: ${obj_type}`);
return false;
}
endpoint = `/v2${endpoint}`;
if (log_lvl) {
console.log('Endpoint:', endpoint);
}
if (for_obj_type) {
params['for_obj_type'] = for_obj_type;
}
if (for_obj_id) {
params['for_obj_id'] = for_obj_id;
}
if (use_alt_tbl === true) {
params['tbl_alt'] = 'alt'; // Use alternate table or view name
}
if (use_alt_mdl === true) {
params['mdl_alt'] = 'alt'; // Use alternate model name
}
if (use_alt_exp === true) {
params['exp_alt'] = 'alt'; // Use alternate export table or view name
}
/* Need to deal with inc params here */
let allowed_enabled_list = ['all', 'enabled', 'not_enabled']
if (allowed_enabled_list.includes(enabled) ) {
params['enabled'] = enabled;
}
let allowed_hidden_list = ['all', 'hidden', 'not_hidden'];
if (allowed_hidden_list.includes(hidden) ) {
params['hidden'] = hidden;
}
// NOTE: The order_by_li variable is in the "headers" because if is a the URL GET params do not handle multiple values very well. Maybe base64 encore in the future or something? Reminder that GET requests should not have a body (no JSON).
// NOTE: The order_by_li should be a key value pair of the property/DB field to sort and how to sort (ASC or DESC)
if (order_by_li) {
headers['order_by_li'] = order_by_li;
}
if (limit >= 0) {
params['limit'] = limit;
}
if (offset >= 0) {
params['offset'] = offset;
}
if (params_json) {
// NOTE: This is a JSON object that needs to be safely converted to a string for the params. This is used for the search endpoint.
// Max characters for a GET request is 2083. This is a limitation of the browser (Microsoft IE and Edge).
if (log_lvl) {
console.log('JSON Object:', params_json);
console.log(JSON.stringify(params_json));
}
// NOTE: "jp" stands for "JSON Params"
params['jp'] = encodeURIComponent(JSON.stringify(params_json));
if (params['jp'].length > 2083) {
console.log(`The JSON object is too large to be used as a GET parameter. The overall max URL length is 2083 characters. Please use the POST endpoint instead. Length = ${params['jp'].length} [THIS DOES NOT EXIST YET]`);
return false;
}
}
// if (json_obj) {
// // NOTE: This is a JSON object that needs to be safely converted to a string for the params. This is used for the search endpoint.
// // Max characters for a GET request is 2083. This is a limitation of the browser (Microsoft IE and Edge).
// console.log('JSON Object:', json_obj);
// params['json_str'] = encodeURIComponent(JSON.stringify(json_obj));
// if (params['json_str'].length > 2083) {
// console.log(`The JSON object is too large to be used as a GET parameter. The overall max URL length is 2083 characters. Please use the POST endpoint instead. Length = ${params['json_str'].length} [THIS DOES NOT EXIST YET]`);
// return false;
// }
// }
if (log_lvl) {
console.log('Params:', params);
}
let object_li_get_promise = await get_object({
api_cfg: api_cfg,
endpoint: endpoint,
headers: headers,
params: params,
return_meta: return_meta,
log_lvl: log_lvl
});
if (log_lvl > 1) {
console.log(object_li_get_promise);
}
return object_li_get_promise;
}

394
src/lib/api_get_object.ts Normal file
View File

@@ -0,0 +1,394 @@
import axios from 'axios';
import type { key_val } from '$lib/ae_stores';
export let temp_get_blob_percent_completed = 0;
// export let get_blob_percent_completed = readable(temp_get_blob_percent_completed);
export let get_blob_percent_completed = temp_get_blob_percent_completed;
export let temp_get_object_percent_completed = 0;
// export let get_object_percent_completed = readable(temp_get_object_percent_completed);
export let get_object_percent_completed = temp_get_object_percent_completed;
// Updated 2024-05-23
export let get_object = async function get_object(
{
api_cfg=null,
endpoint='',
headers={},
params={},
data={},
timeout=60000,
return_meta=false,
return_blob=false,
filename='',
auto_download=false,
as_list=false,
// The task_id value should be a random string that is unique to the task. This is used to identify the task in the message event.
task_id=crypto.randomUUID(),
log_lvl=0
}: {
api_cfg: any,
endpoint: string,
headers?: any,
params?: any,
data?: any,
timeout?: number,
return_meta?: boolean,
return_blob?: boolean,
filename?: null|string,
auto_download?: boolean,
as_list?: boolean,
task_id?: string,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** get_object() *** Endpoint: ${endpoint} AE Task ID: ${task_id}`);
console.log('Params:', params);
if (log_lvl > 1) {
console.log('Data:', data);
console.log(`Base URL: ${api_cfg['base_url']}`);
console.log('API Config:', api_cfg);
}
if (log_lvl > 2) {
console.log(`Return Meta: ${return_meta}`);
console.log(`Return Blob: ${return_blob}`);
console.log(`Filename: ${filename}`);
console.log(`Auto Download: ${auto_download}`);
}
}
if (!api_cfg) {
console.log('No API Config was provided. Returning false.');
return false;
}
let axios_api = axios.create({
baseURL: api_cfg['base_url'],
timeout: timeout, // in milliseconds; 60000 = 60 seconds
/* other custom settings */
});
axios_api.defaults.headers = api_cfg['headers'];
if (log_lvl) {
console.log('axios_api.defaults.headers:', axios_api.defaults.headers);
console.log('Additional headers:', headers);
}
// console.log('Clean the headers. No _underscores_!')
let headers_cleaned: key_val = {};
for (const prop in headers) {
// No underscores allowed in the header parameters!
let prop_cleaned = prop.replaceAll('_', '-');
// The value must be a string for the header!
if (typeof headers[prop] != 'string') {
headers[prop] = JSON.stringify(headers[prop]);
}
headers_cleaned[prop_cleaned] = headers[prop];
if (log_lvl) {
console.log(`${prop_cleaned}: ${headers_cleaned[prop_cleaned]}`);
}
}
headers = headers_cleaned;
if (log_lvl) {
console.log('All headers cleaned:', headers);
}
if (log_lvl) {
console.log('URL params:');
}
for (const prop in params) {
if (log_lvl) {
console.log(`URL param: ${prop}: ${params[prop]}`);
}
if (params[prop] === null ) {
params[prop] = 'null';
}
}
if (!return_blob) {
let response_data_promise = await axios_api.get(
endpoint,
{
headers: headers,
params: params,
onDownloadProgress: (progressEvent) => {
let percent_completed = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
if (log_lvl) {
console.log('GET Data Progress:', progressEvent.progress, 'Total:', progressEvent.total, 'Loaded:', progressEvent.loaded, 'Percent Completed', percent_completed);
}
temp_get_object_percent_completed = percent_completed;
// WARNING: This needs to be tied to an object type and ID. This is a temporary solution.
try {
// Check if window is defined. This is to prevent errors in SvelteKit.
if (typeof window !== 'undefined') {
window.postMessage({
type: 'api_download_data',
status: 'downloading',
task_id: task_id,
endpoint: endpoint,
filename: filename,
size_total: progressEvent.total,
size_loaded: progressEvent.loaded,
percent_completed: percent_completed,
},
'*'
);
}
} catch (error) {
console.log('Error posting message to window:', error);
}
}
}
)
.then(function (response) {
if (log_lvl) {
console.log(`GET Response: status=${response.status} statusText=${response.statusText} baseURL=${response.config.baseURL} url=${response.config.url} method=${response.config.method} headers=${response.config.headers} params=${JSON.stringify(response.config.params)}`);
}
if (log_lvl > 1) {
console.log('GET Response:', response);
}
// Post file download message
try {
if (typeof window !== 'undefined') {
window.postMessage({
type: 'api_download_data',
status: 'complete',
task_id: task_id,
endpoint: endpoint,
filename: filename,
size_total: 0,
size_loaded: 0,
percent_completed: 100,
},
'*'
);
}
} catch (error) {
console.log('Error posting message to window:', error);
}
if (!Array.isArray(response.data['data']) && as_list) {
if (log_lvl) {
console.log('Data result is a dictionary/object, not an array/list. Forcing return as an array/list');
}
let return_data = [];
return_data.push(response.data['data']);
return return_data;
} else if (response.data['data']) {
let return_data = response.data['data'];
if (log_lvl) {
if (Array.isArray(return_data)) {
console.log(`Data result is an array/list. Array length: ${return_data.length}`);
} else {
console.log(`Data result is a dictionary/object, not an array/list.`);
}
}
return return_data;
} else {
let return_data = response.data;
if (log_lvl) {
if (Array.isArray(return_data)) {
console.log(`Not a standard response from Aether's API. Data result is an array/list. Array length: ${return_data.length}`);
} else {
console.log(`Not a standard response from Aether's API. Data result is a dictionary/object, not an array/list.`);
}
}
return return_data;
}
})
.catch(function (error) {
if (log_lvl) {
console.log(`Base URL: ${api_cfg['base_url']} | Endpoint: ${endpoint}`);
console.log('Error Message:', error.message); // Is this needed here or below in the in the else portion???
if (error.response) {
// The request was made and the server responded with a status code that falls out of the range of 2xx
console.log('Error Response Data', error.response.data);
console.log('Error Response Status', error.response.status);
console.log('Error Response Headers', error.response.headers);
} else if (error.request) {
// The request was made but no response was received `error.request` is an instance of XMLHttpRequest in the browser and an instance of http.ClientRequest in node.js
if (log_lvl > 1) {
console.log('Error Request', error.request);
}
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error Message', error.message);
}
}
if (log_lvl > 2) {
console.log('Error:', error);
console.log(error.config);
}
if (error.response && error.response.status === 404) {
if (log_lvl) {
console.log('The response was a 404 not found "error". Returning null.');
}
if (log_lvl > 1) {
console.log(error.response);
}
if (log_lvl > 2) {
console.log(error);
}
return null; // Returning null since there were no results
}
if (error.code === 'ECONNABORTED') {
// Timeout Error (You can implement retry here where suitable)
console.log('Timeout Error: ', error.message);
}
if (log_lvl) {
console.log('The response was an error. Returning false.');
}
return false; // Returning false since something may have gone wrong. This includes timeouts. Also more in line with what the API returns.
// return error;
});
if (log_lvl > 1) {
// console.log(`Response Data: ${response_data_promise}`);
console.log(`Response Data:`, response_data_promise);
// console.log(response_data_promise);
}
if (response_data_promise) {
// The most common and expected response.
// console.log('Returning result. This is generally expected.');
return response_data_promise;
} else if (response_data_promise === null) {
// Less common, but expected response if no results were returned.
console.log('Returning null. This is expected if no results were found.');
return response_data_promise;
} else if (response_data_promise === false) {
// Not common, but expected response if the request to the API had an issue.
console.log('Returning false. There may have been an issue with this request.');
return response_data_promise;
} else {
// This generally should not happen. It likely means the query was bad or an API issue.
console.log('Returning unknown. This should not happen in most cases.');
Promise.reject(new Error('fail')).then(resolved, rejected);
}
} else {
// console.log('Expecting a Blob to be returned...');
let response_data_promise = await axios_api.get(
endpoint,
{
params: params,
responseType: 'blob',
onDownloadProgress: (progressEvent) => {
let percent_completed = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.log('GET Blob Progress:', progressEvent.progress, 'Total:', progressEvent.total, 'Loaded:', progressEvent.loaded, 'Percent Completed', percent_completed);
temp_get_blob_percent_completed = percent_completed;
// WARNING: This needs to be tied to an object type and ID. This is a temporary solution.
try {
if (typeof window !== 'undefined') {
window.postMessage({
type: 'api_download_blob',
status: 'downloading',
task_id: task_id,
endpoint: endpoint,
filename: filename,
size_total: progressEvent.total,
size_loaded: progressEvent.loaded,
percent_completed: percent_completed,
},
'*'
);
}
} catch (error) {
console.log('Error posting message to window:', error);
}
}
}
)
.then(function (response) {
if (log_lvl) {
console.log(`GET (blob) Response: status=${response.status} statusText=${response.statusText} baseURL=${response.config.baseURL} url=${response.config.url} method=${response.config.method} headers=${response.config.headers} params=${response.config.params}`);
}
if (log_lvl > 1) {
console.log('GET (blob) Response:', response);
}
const { data, headers } = response;
// Careful if this download filename needs to be changed to a different file extension. The browser/client may not know how to handle it.
if (filename) {
} else if (headers['content-disposition']) {
filename = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1');
} else {
filename = 'unknown_file.ext';
}
// WARNING: This needs to be tied to an object type and ID. This is a temporary solution.
try {
if (typeof window !== 'undefined') {
window.postMessage({
type: 'api_download_blob',
status: 'complete',
task_id: task_id,
endpoint: endpoint,
filename: filename,
size_total: 0,
size_loaded: 0,
percent_completed: 100,
},
'*'
);
}
} catch (error) {
console.log('Error posting message to window:', error);
}
if (auto_download) {
if (log_lvl) {
console.log(`Auto Download: ${filename}`);
}
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', filename);
document.body.appendChild(link);
link.click();
return true;
} else {
return response;
}
});
if (response_data_promise) {
// The most common and expected response.
// console.log('Returning result. This is generally expected.');
// let test_blob = new Blob([response_data_promise.data]);
// console.log(test_blob);
// return test_blob;
// console.log(response_data_promise.blob());
return response_data_promise;
} else {
// This generally should not happen. It likely means the query was bad or an API issue.
console.log('Returning (blob) unknown. This should not happen in most cases.');
Promise.reject(new Error('fail')).then(resolved, rejected);
}
}
}
function resolved(result: any) {
console.log('Resolved');
}
function rejected(result: any) {
console.error(result);
}

View File

@@ -0,0 +1,60 @@
import axios from 'axios';
// Updated 2024-05-23
export let patch_object = async function patch_object(
{
api_cfg=null,
endpoint='',
params={},
data={},
return_meta=false,
log_lvl=0
}: {
api_cfg: any,
endpoint: string,
params?: any,
data?: any,
return_meta?: boolean,
log_lvl?: number
}
) {
console.log('*** patch_object() ***');
if (log_lvl) {
// console.log(api_cfg);
console.log(endpoint);
console.log(params);
if (log_lvl > 1) {
console.log(data);
}
// console.log(return_meta);
// console.log(as_list);
}
let axios_api = axios.create({
baseURL: api_cfg['base_url'],
/* other custom settings */
});
axios_api.defaults.headers = api_cfg['headers'];
let response_data = await axios_api.patch(endpoint, data, { params: params })
.then(function (response) {
console.log(response.data);
return response.data['data'];
//return response.data;
})
.catch(function (error) {
if (error.response && error.response.status === 404) {
return null; // Returning null since there were no results
}
console.log(error);
return false; // Returning false since something may have gone wrong. Also more in line with what the API returns.
// return error;
});
if (log_lvl > 1) {
console.log(response_data);
}
return response_data;
}

224
src/lib/api_post_object.ts Normal file
View File

@@ -0,0 +1,224 @@
import axios from 'axios';
export let temp_post_blob_percent_completed = 0;
export let post_blob_percent_completed = temp_post_blob_percent_completed;
export let temp_post_object_percent_completed = 0;
export let post_object_percent_completed = temp_post_object_percent_completed;
// Updated 2024-05-23
export let post_object = async function post_object(
{
api_cfg=null,
endpoint='',
params={},
data={},
form_data=null,
return_meta=false,
return_blob=false,
filename='',
auto_download=false,
// The task_id value should be a random string that is unique to the task. This is used to identify the task in the message event.
task_id=crypto.randomUUID(),
log_lvl=0
}: {
api_cfg: any,
endpoint: string,
params?: any,
data?: any,
form_data?: any,
return_meta?: boolean,
return_blob?: boolean,
filename?: string,
auto_download?: boolean,
task_id?: string,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** post_object() *** Endpoint: ${endpoint} Task ID: ${task_id}`);
console.log('Params:', params);
if (log_lvl > 1) {
console.log('Data:', data);
console.log(typeof data);
console.log(`Base URL: ${api_cfg['base_url']}`);
console.log('API Config:', api_cfg);
}
if (log_lvl > 2) {
console.log(`Return Meta: ${return_meta}`);
console.log(`Return Blob: ${return_blob}`);
console.log(`Filename: ${filename}`);
console.log(`Auto Download: ${auto_download}`);
}
// console.log(return_meta);
}
let axios_api = axios.create({
baseURL: api_cfg['base_url'],
/* other custom settings */
});
axios_api.defaults.headers = api_cfg['headers'];
console.log('Axios API', axios_api);
// console.log('Axios API POST', axios_api.post);
// if (typeof data == 'FormData') {
if (form_data) {
axios_api.defaults.headers['content-type'] = 'multipart/form-data';
data = form_data;
} else {
axios_api.defaults.headers['content-type'] = 'application/json';
}
if (!return_blob) {
let response_data = await axios_api.post(
endpoint,
data,
{
params: params,
onUploadProgress: (progressEvent) => {
let percent_completed = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.log('POST Progress:', progressEvent.progress, 'Total:', progressEvent.total, 'Loaded:', progressEvent.loaded, 'Percent Completed', percent_completed);
temp_post_object_percent_completed = percent_completed;
try {
window.postMessage({
type: 'api_post_json_form',
status: 'uploading',
task_id: task_id,
endpoint: endpoint,
size_total: progressEvent.total,
size_loaded: progressEvent.loaded,
percent_completed: percent_completed,
progress: progressEvent.progress,
rate: progressEvent.rate,
},
'*'
);
} catch (error) {
console.log('Error posting message to window:', error);
}
}
}
)
.then(function (response) {
console.log('POST Response Data:', response.data);
try {
window.postMessage({
type: 'api_post_json_form',
status: 'complete',
task_id: task_id,
endpoint: endpoint,
size_total: 0,
size_loaded: 0,
percent_completed: 100,
progress: 100,
rate: 0,
},
'*'
);
} catch (error) {
console.log('Error posting message to window:', error);
}
if (response.data['data'].result === null) {
// This should mean that the request was successful, but a result of None/null was returned from Aether API.
// console.log('Returning null after POST');
return null;
} else {
// This should mean that the request was successful, and a result with data was returned from Aether API.
// console.log('Returning data after POST');
return response.data['data'];
}
//return response.data;
})
.catch(function (error) {
if (error.response && error.response.status === 404) {
return null; // Returning null since there were no results
}
console.log(error);
return false; // Returning false since something may have gone wrong. Also more in line with what the API returns.
// return error;
});
if (log_lvl > 1) {
console.log('Response Data:', response_data);
}
axios_api.defaults.headers['content-type'] = 'application/json';
return response_data;
} else {
// console.log('Expecting a Blob to be returned...');
let response_data_promise = await axios_api.post(
endpoint,
data,
{
params: params,
responseType: 'blob',
onDownloadProgress: (progressEvent) => {
let percent_completed = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.log('POST Blob Progress:', progressEvent.progress, 'Total:', progressEvent.total, 'Loaded:', progressEvent.loaded, 'Percent Completed', percent_completed);
temp_post_blob_percent_completed = percent_completed;
}
}
)
.then(function (response) {
if (log_lvl) {
console.log(response);
}
const { data, headers } = response
console.log(headers);
if (filename) {
} else if (headers['content-disposition']) {
filename = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1');
} else {
filename = 'unknown_file.ext';
}
if (auto_download) {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
// link.setAttribute('download', 'event_exhibit_tracking_export.xlsx'); //or any other extension
link.setAttribute('download', filename); //or any other extension
document.body.appendChild(link);
link.click();
return true;
} else {
return response;
}
});
if (response_data_promise) {
// The most common and expected response.
// console.log('Returning result. This is generally expected.');
// let test_blob = new Blob([response_data_promise.data]);
// console.log(test_blob);
// return test_blob;
// console.log(response_data_promise.blob());
return response_data_promise;
} else {
// This generally should not happen. It likely means the query was bad or an API issue.
console.log('Returning unknown. This should not happen in most cases.');
Promise.reject(new Error('fail')).then(resolved, rejected);
}
}
}
function resolved(result: any) {
console.log('Resolved');
}
function rejected(result: any) {
console.error(result);
}

97
src/lib/db_core.ts Normal file
View File

@@ -0,0 +1,97 @@
import Dexie, { type Table } from 'dexie';
// li = list
// kv = key value list
// Updated 2024-07-17
export interface Person {
id: string;
// id_random: string;
person_id: string;
person_id_random: string;
external_id?: string; // This may be semi-random or unique only withing the account.
external_sys_id?: string; // Generated by an external system. Ideally this should be something like a UUID. It may be the same as the external_id if nothing given.
code?: string;
account_id?: string; // Technically this is not required for global users.
account_id_random?: string; // Technically this is not required for global users.
person_profile_id?: null|string;
person_profile_id_random?: null|string; // The new table person_profile will be used soon...
user_id?: string;
user_id_random?: string;
pronouns?: null|string;
informal_name?: null|string;
title_names?: null|string;
given_name: string;
middle_name?: null|string;
family_name: null|string;
designations?: null|string;
professional_title?: null|string;
full_name?: string;
affiliations?: null|string;
primary_email?: string;
biography?: null|string;
agree?: null|boolean;
comments?: null|string;
allow_auth_key?: null|boolean; // For sign in without password
auth_key?: null|string;
passcode?: null|string;
data_json?: null|string;
enable: null|boolean;
hide?: null|boolean;
priority?: null|boolean
sort?: null|number;
group?: null|string;
notes?: null|string;
created_on: Date;
updated_on?: null|Date;
// Additional fields for convenience (database views)
username?: string;
user_name?: null|string;
user_email?: null|string;
user_allow_auth_key?: null|boolean; // For sign in without password
user_super?: boolean;
user_manager?: boolean;
user_administrator?: boolean;
user_public?: boolean;
}
// Updated 2024-06-24
export class MySubClassedDexie extends Dexie {
person!: Table<Person>;
// user!: Table<User>;
constructor() {
super('ae_core_db');
this.version(1).stores({
person: `
id, person_id, person_id_random,
external_id, code,
account_id, user_id,
account_id_random, user_id_random,
person_profile_id,
person_profile_id_random,
given_name, family_name,
full_name, affiliations, email,
agree,
enable, hide, priority, sort, group, created_on, updated_on`,
});
}
}
export const db_core = new MySubClassedDexie();

643
src/lib/db_events.ts Normal file
View File

@@ -0,0 +1,643 @@
import Dexie, { type Table } from 'dexie';
import type { key_val } from './ae_stores';
// li = list
// kv = key value list
export interface Event {
id: string;
// id_random: string;
event_id: string;
event_id_random: string;
code: string;
account_id: string;
account_id_random: string;
conference: boolean;
type: string;
name: string;
summary?: null|string;
description?: null|string;
start_datetime?: Date;
end_datetime?: Date;
timezone?: null|string;
location_address_json?: null|string;
mod_abstracts_json?: null|key_val;
mod_badges_json?: null|key_val;
mod_exhibits_json?: null|key_val;
mod_pres_mgmt_json?: null|key_val;
cfg_json?: null|key_val;
enable: null|boolean;
hide: null|boolean;
priority: null|boolean
sort: null|number;
group: null|string;
notes: null|string;
created_on: Date;
updated_on: null|Date;
// Additional fields for convenience (database views)
file_count?: null|number;
file_count_all?: null|number;
internal_use_count?: null|number;
event_file_id_li_json?: null|string;
}
export interface Badge {
// id?: number;
id_random: string;
event_badge_id_random: string;
event_id_random: string;
pronouns: null|string;
informal_name: null|string;
title_names: null|string;
given_name: string;
middle_name: null|string;
family_name: null|string;
designations: null|string;
professional_title: null|string;
professional_title_override: null|string;
full_name: string;
full_name_override: null|string;
affiliations: string;
affiliations_override: null|string;
email: string;
email_override: null|string;
address_line_1: null|string;
address_line_2: null|string;
address_line_3: null|string;
city: null|string;
country_subdivision_code: null|string;
state_province: null|string;
state_province_abb: null|string;
postal_code: null|string;
country_alpha_2_code: null|string;
country: null|string;
full_address: null|string;
location: null|string;
location_override: null|string;
query_str: null|string;
badge_type: string;
badge_type_code: string;
badge_type_code_override: null|string;
badge_type_override: null|string;
external_event_id: string;
external_id: string;
external_person_id: string;
enable: null|boolean;
hide: null|boolean;
priority: null|boolean
sort: null|number;
group: null|string;
notes: null|string;
created_on: Date;
updated_on: null|Date;
}
export interface Exhibit {
// id?: number;
id_random: string;
event_exhibit_id_random: string;
event_id_random: string;
code: string;
name: string;
// tagline: null|string;
description: null|string;
staff_passcode: null
data_json: null|string;
leads_api_access: null|boolean;
leads_custom_questions_json: null|string;
leads_device_sm_qty: null|number;
leads_device_lg_qty: null|number;
license_max: number;
license_li_json: null|string;
cfg_json: string;
enable: null|boolean;
hide: null|boolean;
priority: null|boolean
sort: null|number;
group: null|string;
notes: null|string;
created_on: Date;
updated_on: null|Date;
}
export interface Exhibit_tracking {
// id?: number;
id_random: string;
event_exhibit_tracking_id_random: string;
event_exhibit_id_random: string;
event_badge_id_random: string;
event_person_id_random: null|string; // Is this needed?
external_person_id: null|string; // This is an email address
exhibitor_notes: null|string;
responses_json: null|string;
data_json: null|string;
event_exhibit_name: string; // Extra field for convenience
event_badge_title_names: null|string;
event_badge_given_name: string;
event_badge_family_name: null|string;
event_badge_designations: null|string;
event_badge_full_name: string;
event_badge_full_name_override: null|string;
event_badge_professional_title: null|string;
event_badge_professional_title_override: null|string;
event_badge_affiliations: null|string;
event_badge_affiliations_override: null|string;
event_badge_email: null|string;
event_badge_email_override: null|string;
event_badge_location: null|string;
event_badge_location_override: null|string;
event_badge_country: null|string;
enable: null|boolean;
hide: null|boolean;
priority: null|boolean
sort: null|number;
group: null|string;
notes: null|string;
created_on: Date;
updated_on: null|Date;
}
export interface Registration {
// Nothing here yet
}
export interface File {
id: string;
id_random: string;
event_file_id: string;
event_file_id_random: string;
hosted_file_id: string;
hosted_file_id_random: string;
hash_sha256: string;
for_type?: string;
for_id?: string;
for_id_random?: string;
event_id_random: string;
event_session_id_random?: string;
event_presentation_id_random?: string;
event_presenter_id_random?: string;
event_location_id_random?: string;
filename: string;
extension: string;
open_in_os?: null|string; // null, empty, 'mac', or 'win'
lu_file_purpose_id: string;
lu_event_file_purpose_name: string;
file_purpose: string;
enable: null|boolean;
hide?: null|boolean;
priority?: null|boolean
sort?: null|number;
group?: null|string;
notes?: null|string;
created_on: Date;
updated_on?: null|Date;
// Additional fields for convenience (database views)
filename_no_ext: string;
filename_w_ext: string;
hosted_file_content_type: string;
file_size: number; // In bytes
hosted_file_size?: number; // In bytes
event_location_code?: null|string;
event_location_name?: null|string;
event_session_code?: null|string;
event_session_name?: string;
event_session_start_datetime?: null|Date;
event_presentation_code?: null|string;
event_presentation_name?: string;
event_presentation_start_datetime?: null|Date;
event_presenter_given_name?: null|string;
event_presenter_family_name?: null|string;
event_presenter_full_name?: null|string;
event_presenter_email?: null|string;
}
// Updated 2024-06-25
export interface Location {
id: string;
// id_random: string;
event_location_id: string;
event_location_id_random: string;
external_id?: null|string;
code?: null|string;
type_code?: string;
event_id: string;
event_id_random: string;
name: string;
description?: null|string;
passcode?: null|string;
hide_event_launcher?: null|boolean;
alert?: null|boolean;
alert_msg?: null|string;
data_json?: null|string;
enable: null|boolean;
hide?: null|boolean;
priority?: null|boolean
sort?: null|number;
group?: null|string;
notes?: null|string;
created_on: Date;
updated_on?: null|Date;
// Additional fields for convenience (database views)
file_count?: null|number;
file_count_all?: null|number;
internal_use_count?: null|number;
event_file_id_li_json?: null|string;
event_name?: null|string;
// A key value list of the sessions
event_session_kv?: null|key_val;
// A key value list of the files
event_file_kv?: null|key_val;
}
// Updated 2024-06-19
export interface Session {
id: string;
// id_random: string;
event_session_id: string;
event_session_id_random: string;
external_id: null|string;
code: null|string;
for_type: string;
for_id: string;
for_id_random: string;
type_code?: string;
event_id: string;
event_id_random: string;
event_location_id?: null|string;
event_location_id_random?: null|string;
poc_person_id?: null|string;
poc_person_id_random?: null|string;
name: string;
description?: null|string;
start_datetime?: null|Date;
end_datetime?: null|Date;
passcode?: null|string;
hide_event_launcher?: null|boolean;
alert?: null|boolean;
alert_msg?: null|string;
data_json?: null|string;
ux_mode?: null|string; // 'colloquium', 'lecture', 'panel', 'poster', 'symposium', 'workshop'
// colloquium - Specialists present on related topics with questions
// symposium - A discussion, less formal
enable: null|boolean;
hide: null|boolean;
priority: null|boolean
sort: null|number;
group: null|string;
notes: null|string;
created_on: Date;
updated_on: null|Date;
// Additional fields for convenience (database views)
file_count?: null|number; // Only files directly under a session
file_count_all?: null|number; // All files under a session
internal_use_count?: null|number; // Files marked for internal use
event_file_id_li_json?: null|string;
poc_person_given_name?: null|string;
poc_person_family_name?: null|string;
poc_person_full_name?: null|string;
poc_person_primary_email?: null|string;
poc_person_passcode?: null|string;
poc_kv_json?: null|string;
event_name?: null|string;
event_location_code?: null|string;
event_location_name?: null|string;
// A key value list of the presentations
event_presentation_kv?: null|key_val;
event_presentation_li?: null|list;
// A key value list of the files
event_file_kv?: null|key_val;
event_file_li?: null|list;
}
// Updated 2024-06-10
export interface Presentation {
id: string;
// id_random: string;
event_presentation_id: string;
event_presentation_id_random: string;
external_id?: null|string;
code?: null|string;
for_type?: string;
for_id?: string;
for_id_random?: string;
type_code?: string;
event_id: string;
event_id_random: string;
event_session_id: string;
event_session_id_random: string;
event_abstract_id?: null|string;
event_abstract_id_random?: null|string;
abstract_code?: null|string;
name: string;
description?: null|string;
start_datetime?: null|Date;
end_datetime?: null|Date;
passcode?: null|string;
hide_event_launcher?: null|boolean;
enable: null|boolean;
hide?: null|boolean;
priority?: null|boolean;
sort?: null|number;
group?: null|string;
notes?: null|string;
created_on: Date;
updated_on?: null|Date;
// Additional fields for convenience (database views)
// file_count: null|number;
event_session_code?: null|string;
event_session_name?: null|string;
// A key value list of the presenters
event_presenter_kv?: null|key_val;
event_presenter_li?: null|list;
}
// Updated 2024-06-10
export interface Presenter {
id: string;
// id_random: string;
event_presenter_id: string;
event_presenter_id_random: string;
external_id?: string;
code?: string;
event_id: string;
event_id_random: string;
event_session_id: string;
event_session_id_random: string;
event_person_id?: null|string;
event_person_id_random?: null|string;
event_presentation_id: string;
event_presentation_id_random: string;
person_id?: null|string;
person_id_random?: null|string;
person_profile_id?: null|string;
person_profile_id_random?: null|string; // The new table person_profile will be used soon...
pronouns?: null|string;
informal_name?: null|string;
title_names?: null|string;
given_name: string;
middle_name?: null|string;
family_name?: null|string;
designations?: null|string;
professional_title?: null|string;
full_name?: string;
affiliations?: null|string;
email?: string;
biography?: null|string;
agree?: null|boolean;
comments?: null|string;
passcode?: null|string;
hide_event_launcher?: null|boolean;
data_json?: null|string;
enable: null|boolean;
hide?: null|boolean;
priority?: null|boolean
sort?: null|number;
group?: null|string;
notes?: null|string;
created_on?: Date;
updated_on?: null|Date;
// Additional fields for convenience (database views)
file_count?: null|number;
// file_count_all?: null|number;
// internal_use_count?: null|number;
event_file_id_li_json?: null|string;
event_session_code?: null|string;
event_session_name?: string;
event_session_start_datetime?: null|Date;
event_presentation_code?: null|string;
event_presentation_name?: string;
event_presentation_start_datetime?: null|Date;
person_external_id?: null|string; // This may be semi-random or unique only withing the account.
person_external_sys_id?: null|string; // Generated by an external system. Ideally this should be something like a UUID. It may be the same as the external_id if nothing given.
person_given_name?: string;
person_family_name?: null|string;
person_full_name?: null|string;
person_professional_title?: null|string;
person_affiliations?: null|string;
person_primary_email?: null|string;
person_passcode?: null|string;
// A key value list of the files
event_file_kv?: null|key_val;
}
// Updated 2024-06-10
export class MySubClassedDexie extends Dexie {
// 'badges' is added by dexie when declaring the stores()
// We just tell the typing system this is the case
events!: Table<Event>;
badges!: Table<Badge>;
exhibits!: Table<Exhibit>;
exhibit_tracking!: Table<Exhibit_tracking>;
files!: Table<File>;
locations!: Table<Location>;
sessions!: Table<Session>;
presentations!: Table<Presentation>;
presenters!: Table<Presenter>;
constructor() {
super('ae_events_db');
this.version(2).stores({
events: `
id, event_id, event_id_random,
code,
account_id, account_id_random,
conference, type,
name,
start_datetime, end_datetime,
timezone,
cfg_json,
enable, hide, priority, sort, group, notes, created_on, updated_on`,
// badges: '++id, full_name, email' // Primary key and indexed props
badges: `
id_random, event_badge_id_random, event_id_random,
full_name, full_name_override, email, email_override,
affiliations, affiliations_override,
badge_type, badge_type_code, badge_type_code_override, badge_type_override,
external_event_id, external_id, external_person_id,
enable, hide, priority, sort, group, notes, created_on, updated_on`,
exhibits: `
id_random, event_exhibit_id_random,
code, name, description, staff_passcode,
data_json, license_max, license_li_json, cfg_json,
enable, hide, priority, sort, group, notes, created_on, updated_on, [priority+name]`,
exhibit_tracking: `
id_random, event_exhibit_tracking_id_random, event_exhibit_id_random, event_badge_id_random, event_person_id_random,
exhibitor_notes, responses_json, data_json,
event_badge_full_name, event_badge_email,
enable, hide, priority, sort, group, notes, created_on, updated_on`,
sessions: `
id, event_session_id, event_session_id_random,
external_id, code,
for_type, for_id, for_id_random,
type_code,
event_id, event_location_id,
poc_person_id,
event_id_random, event_location_id_random,
poc_person_id_random,
name, start_datetime, end_datetime,
hide_event_launcher,
ux_mode,
enable, hide, priority, sort, group, created_on, updated_on`,
files: `
id, id_random, event_file_id, event_file_id_random,
hosted_file_id, hosted_file_id_random,
hash_sha256,
for_type, for_id, for_id_random,
event_id_random, event_session_id_random, event_presentation_id_random, event_presenter_id_random, event_location_id_random,
filename, extension,
lu_file_purpose_id, lu_event_file_purpose_name, file_purpose,
enable, hide, priority, sort, group, created_on, updated_on`,
locations: `
id, event_location_id, event_location_id_random,
external_id, code,
event_id, event_id_random,
name, description,
passcode,
hide_event_launcher,
alert, alert_msg,
data_json,
enable, hide, priority, sort, group, created_on, updated_on`,
presentations: `
id, event_presentation_id, event_presentation_id_random,
external_id, code,
for_type, for_id, for_id_random,
type_code,
event_id_random, event_session_id_random, event_abstract_id_random,
abstract_code, name, description, start_datetime, end_datetime,
hide_event_launcher,
enable, hide, priority, sort, group, created_on, updated_on`,
presenters: `
id, event_presenter_id, event_presenter_id_random,
external_id, code,
event_id, event_session_id, event_person_id, event_presentation_id,
event_id_random, event_session_id_random, event_person_id_random, event_presentation_id_random,
person_id, person_profile_id,
person_id_random, person_profile_id_random,
given_name, family_name,
full_name, affiliations, email,
agree,
hide_event_launcher,
enable, hide, priority, sort, group, created_on, updated_on`,
});
}
}
export const db_events = new MySubClassedDexie();

147
src/lib/db_notes.ts Normal file
View File

@@ -0,0 +1,147 @@
import Dexie, { type Table } from 'dexie';
import type { key_val } from './ae_stores';
// li = list
// kv = key value list
// json = JSON string
// ux = user experience (mode)
// LLM = Large Language Model (AI)
// Updated 2024-08-20
export interface Note {
id: string; // actually "id_random"
note_id: string;
// Essentially this is a change log of notes
snapshot_id: string; // This is the original note ID. If deleted, then delete all children notes.
previous_id?: null|string; // This is the old or parent note ID
next_id?: null|string; // This is the new or child note ID
external_id?: null|string;
import_id?: null|string;
code?: null|string;
for_type?: null|string;
for_id?: null|string;
type_code?: null|string;
account_id?: null|string; // Owner account of the note
person_id?: null|string; // Owner person of the note
event_id: null|string; // Assign to an event???
location_id?: null|string; // Assign to a location???
name: string; // or the title
summary?: null|string; // LLM (AI) generated summary...???
outline?: null|string; // LLM (AI) generated outline...???
note?: null|string;
note_html?: null|string;
note_json?: null|string;
start_datetime?: null|Date;
end_datetime?: null|Date;
timezone?: null|string;
hide_event_launcher?: null|boolean;
alert?: null|boolean; // LLM (AI) generated summary...???
alert_msg?: null|string; // LLM (AI) generated summary...???
data_json?: null|string; // We always need to store something extra...
ux_mode?: null|string; // 'mobile' or 'desktop'
// This only allows for basic access to the content.
passcode_read?: null|string; // For LLM (AI) generated summary...???
passcode_read_expire?: null|Date;
passcode_write?: null|string;
passcode_write_expire?: null|Date
enable: null|boolean;
hide: null|boolean;
priority: null|boolean
sort: null|number;
group: null|string;
notes: null|string;
created_on: Date;
updated_on: null|Date;
// Additional fields for convenience (database views)
file_count?: null|number; // Only files directly under a note
note_file_id_li_json?: null|string;
// One person
person__given_name?: null|string;
person__family_name?: null|string;
person__full_name?: null|string;
person__primary_email?: null|string;
person__passcode?: null|string;
// JSON formatted key value pairs for multiple people: {id: name, email, etc.}
person__kv_json?: null|string;
note_name?: null|string;
note_location_code?: null|string;
note_location_name?: null|string;
// A key value list of the presentations
note_presentation_kv?: null|key_val;
note_presentation_li?: null|list;
// A key value list of the files
note_file_kv?: null|key_val;
note_file_li?: null|list;
// Future standard fields!!!
obj_id?: null|string;
obj_ext_uid?: null|string; // Probably not needed for notes
obj_ext_id?: null|string; // Probably not needed for notes
obj_import_id?: null|string; // Probably not needed for notes
obj_code?: null|string;
obj_account_id?: null|string;
obj_passcode?: null|string;
obj_type?: null|string; // Should always be 'note' in this case
obj_type_ver_id?: null|string; // The ID from the table for the object type
obj_name?: null|string;
obj_summary?: null|string; // LLM (AI) generated summary...???
obj_outline?: null|string; // LLM (AI) generated outline...???
obj_description?: null|string; // Probably not needed for notes
obj_enable?: null|boolean;
obj_enable_on?: null|Date;
obj_archive_on?: null|Date;
obj_hide?: null|boolean;
obj_priority?: null|number;
obj_sort?: null|number;
obj_group?: null|string;
obj_cfg_json?: null|string;
obj_notes?: null|string; // Not the same as the "note" in the object type named "Note".
obj_created_on?: Date;
obj_updated_on?: null|Date;
}
// Updated 2024-06-10
export class MySubClassedDexie extends Dexie {
// We just tell the typing system this is the case
notes!: Table<Note>;
constructor() {
super('ae_notes_db');
this.version(1).stores({
notes: `
id, note_id, note_id_random,
code,
account_id, account_id_random,
conference, type,
name,
start_datetime, end_datetime,
timezone,
cfg_json,
enable, hide, priority, sort, group, notes, created_on, updated_on`,
});
}
}
export const db_notes = new MySubClassedDexie();

1391
src/lib/electron_native.js Normal file

File diff suppressed because it is too large Load Diff

318
src/lib/electron_relay.js Normal file
View File

@@ -0,0 +1,318 @@
/* ### Electron Specific JavaScript ### */
// import crypto from 'crypto';
// import {fs} from 'fs';
// import path from 'path';
// const crypto = require('crypto');
// const fs = require('fs');
// const fs_promises = require('node:fs/promises');
// const path = require('path');
// const { ipcRenderer } = require('electron');
// function sleep(milliseconds) {
// const date = Date.now();
// let currentDate = null;
// do {
// currentDate = Date.now();
// } while (currentDate - date < milliseconds);
// }
// // exports.check_hash_file_cache should no longer be needed with this.
// // Updated 2022-10-11
// export let check_hash_file_cache_v2 = async function check_hash_file_cache_v2({local_file_cache_path, hash, check_hash=false}) {
// console.log('*** check_hash_file_cache_v2() ***');
// console.log(`Host File Cache Path: ${local_file_cache_path}; Hash: ${hash}`);
// let hash_filename = `${hash}.file`;
// let subdirectory = hash_filename.substring(0,2);
// let subdirectory_path = path.join(local_file_cache_path, subdirectory);
// if (fs.existsSync(subdirectory_path)) {
// } else {
// console.log(`Hashed file subdirectory not found in cache: ${subdirectory_path}`);
// return null;
// }
// let hash_file_cache_path = path.join(subdirectory_path, hash_filename);
// if (fs.existsSync(hash_file_cache_path)) {
// console.log(`Hashed file exists in cache: ${hash_file_cache_path}`);
// if (check_hash) {
// const file_buffer = fs.readFileSync(hash_file_cache_path);
// const file_hash_sha256 = crypto.createHash('sha256');
// file_hash_sha256.update(file_buffer);
// const file_hash_sha256_check = file_hash_sha256.digest('hex');
// if (file_hash_sha256_check == hash) {
// console.log('File hash match', file_hash_sha256_check);
// } else {
// console.log('File hash does not match', file_hash_sha256_check);
// return false;
// }
// }
// return true;
// } else {
// console.log(`Hashed file not found in cache: ${hash_file_cache_path}`);
// return null;
// }
// }
// Updated 2022-05-07
export let kill_processes = async function kill_processes({process_name_li=[]}) {
console.log('*** kill_processes() ***');
console.log(`Process Name List: ${process_name_li}`);
let fail_flag = null;
if (process_name_li) {
for (let i = 0; i < process_name_li.length; i++) {
// separate the keys and the values
let process_name = process_name_li[i];
let signal = null;
if (process_name == 'osit_aperture_wrapper') {
signal = 'INT'; // INT (interrupt) correctly stops the wrapper
}
let kill_processes_result = await native_app.kill_processes({process_name: process_name, signal: signal});
console.log(kill_processes_result);
if (kill_processes_result) {
console.log('Killed process.');
// return kill_processes_result;
} else {
console.log('Did not kill process. Something went wrong.');
fail_flag = true;
// return false;
}
}
}
return fail_flag;
// let kill_processes_result = await native_app.kill_processes({process_name: process_name});
// console.log(kill_processes_result);
// if (kill_processes_result) {
// console.log('Killed process.');
// return kill_processes_result;
// } else {
// console.log('Did not kill process. Something went wrong.');
// return false;
// }
}
// Updated 2022-05-06
export let open_local_file = async function open_local_file({file_path, filename}) {
console.log('*** open_local_file() ***');
console.log(`File Path: ${file_path}; Filename: ${filename}`);
console.log('Process: Check local hash file cache, Download hash file to cache, and Open cached hash file after copying to temp directory');
// let check_local_file_result = await native_app.check_local_file({local_file_path: file_path, filename: filename});
// console.log(check_local_file_result);
// if (check_local_file_result) {
// console.log('Local file found.');
// } else {
// console.log('Local file not found. Will not attempt to open.');
// return false;
// }
// console.log('Local file file found and ready to be opened.');
let open_local_file_result = await native_app.open_local_file({local_file_path: file_path, filename: filename});
console.log(open_local_file_result);
if (open_local_file_result) {
console.log('Local file was opened.');
return open_local_file_result;
} else {
console.log('Local file was not opened. Something went wrong.');
return false;
}
}
// exports.open_local_file should no longer be needed with this.
// Updated 2022-10-11
export let open_local_file_v2 = async function open_local_file_v2({file_path, filename}) {
console.log('*** open_local_file_v2() ***');
console.log(`Local File Path: ${file_path}; Filename: ${filename}`);
console.log('Process: Check local hash file cache, Download hash file to cache, and Open cached hash file after copying to temp directory');
let open_local_file_result = await ipcRenderer.invoke('open_local_file', file_path, filename).then((result) => {
console.log('IPC open local file finished');
if (result) {
console.log('Local file was opened.');
return result;
} else {
console.log('Local file was not opened. Something went wrong.');
console.log(result);
return false;
}
console.log(result);
return true;
})
return open_local_file_result;
}
// // Updated 2022-05-06
// export let open_hash_file_to_temp = async function open_hash_file_to_temp({local_file_cache_path, hash, host_file_temp_path, filename}) {
// console.log('*** open_hash_file_to_temp() ***');
// console.log(`Host File Cache Path: ${local_file_cache_path}; Hash: ${hash}; Host File Temp Path: ${host_file_temp_path}; Filename: ${filename}`);
// console.log('Process: Check local hash file cache, Download hash file to cache, and Open cached hash file after copying to temp directory');
// let open_hash_file_to_temp_result = await native_app.open_hash_file_to_temp({local_file_cache_path: local_file_cache_path, hash: hash, host_file_temp_path: host_file_temp_path, filename: filename});
// console.log(open_hash_file_to_temp_result);
// if (open_hash_file_to_temp_result) {
// console.log('Local hash file was opened from temp directory.');
// return open_hash_file_to_temp_result;
// } else {
// console.log('Local hash file was not opened from the temp directory. Something went wrong.');
// return false;
// }
// }
// // exports.open_hash_file_to_temp should no longer be needed with this.
// // Updated 2022-10-11
// export let open_hash_file_to_temp_v2 = async function open_hash_file_to_temp_v2({local_file_cache_path, hash, host_file_temp_path, filename}) {
// console.log('*** open_hash_file_to_temp_v2() ***');
// console.log(`Host File Cache Path: ${local_file_cache_path}; Hash: ${hash}; Host File Temp Path: ${host_file_temp_path}; Filename: ${filename}`);
// console.log('Process: Check local hash file cache, Download hash file to cache, and Open cached hash file after copying to temp directory');
// let subdirectory = hash.substring(0,2);
// let subdirectory_path = path.join(local_file_cache_path, subdirectory);
// if (fs.existsSync(subdirectory_path)) {
// } else {
// console.log(`Hashed file subdirectory not found in cache: ${subdirectory_path}`);
// return null;
// }
// let hash_filename = hash+'.file';
// let full_cache_file_path = path.join(subdirectory_path, hash_filename);
// console.log(full_cache_file_path);
// const file_buffer = fs.readFileSync(full_cache_file_path);
// const file_hash_sha256 = crypto.createHash('sha256');
// file_hash_sha256.update(file_buffer);
// const file_hash_sha256_check = file_hash_sha256.digest('hex');
// if (file_hash_sha256_check == hash) {
// console.log('File hash match', file_hash_sha256_check);
// } else {
// console.log('File hash does not match', file_hash_sha256_check);
// // await setTimeout(async () => {console.log('Done waiting????'); open_file_clicked = false;}, 5000);
// // sleep(6000);
// // console.log('???????? WAITED X SECONDS ????????');
// return false;
// }
// let open_hash_file_to_temp_result = await ipcRenderer.invoke('open_hash_file_to_temp', subdirectory_path, hash, host_file_temp_path, filename).then((result) => {
// console.log('IPC open hash file to temp finished');
// if (result) {
// console.log('Local hash file was opened from temp directory.');
// return result;
// } else {
// console.log('Local hash file was not opened from the temp directory. Something went wrong.');
// console.log(result);
// return false;
// }
// })
// return open_hash_file_to_temp_result;
// }
// Updated 2022-05-07
export let run_cmd = async function run_cmd({cmd=null, return_stdout=null}) {
console.log('*** run_cmd() ***');
let run_cmd_result = await native_app.run_cmd({cmd: cmd, return_stdout: return_stdout})
.then(function (result) {
if (result) {
console.log('Command ran');
} else {
console.log('Command did not run. Something went wrong.');
return false;
}
if (return_stdout) {
return result;
} else {
return true;
}
});
console.log('Run Command Result:', run_cmd_result);
return run_cmd_result;
}
// Updated 2022-10-27
export let run_cmd_sync = function run_cmd_sync({cmd=null, return_stdout=null}) {
console.log('*** run_cmd_sync() ***');
let run_cmd_result = native_app.run_cmd_sync({cmd: cmd, return_stdout: return_stdout});
// if (run_cmd_result) {
// console.log('Command ran');
// } else {
// console.log('Command did not run. Something went wrong.');
// // return false;
// }
// if (return_stdout) {
// return run_cmd_result;
// } else {
// return true;
// }
console.log('Run Command Result:', run_cmd_result);
return run_cmd_result;
}
// Updated 2022-05-07
export let run_osascript = async function run_osascript({cmd=null, interactive=false, language=null, flags='h', program_file=null}) {
console.log('*** run_osascript() ***');
let run_osascript_result = await native_app.run_osascript({cmd: cmd, interactive: interactive, language: language, flags: flags, program_file: program_file});
console.log(run_osascript_result);
if (run_osascript_result) {
console.log('Apple Script ran');
} else {
console.log('Apple Script did not run. Something went wrong.');
}
return run_osascript_result;
}
// Updated 2022-05-07
export let get_device_info = async function get_device_info({event_device_id}) {
console.log('*** get_device_info() ***');
console.log(event_device_id);
let get_device_info_result = await native_app.get_device_info();
console.log(get_device_info_result);
if (get_device_info_result) {
console.log('Success');
} else {
console.log('Failed? Something went wrong.');
}
return get_device_info_result;
}

View File

@@ -0,0 +1,374 @@
<script lang="ts">
import { createEventDispatcher, onMount, tick } from 'svelte';
// import { liveQuery } from "dexie";
import { ae_util } from '$lib/ae_utils';
import { ae_loc, ae_sess, ae_api, slct, slct_trigger } from '$lib/ae_stores';
// import { events_loc } from '$lib/ae_events_stores';
// import { db_events } from "$lib/db_events";
let entered_passcode: null|string = null;
let show_passcode_input: boolean = false;
let trigger: null|string = null;
const dispatch = createEventDispatcher();
onMount(() => {
console.log('** Element Mounted: ** Element Access Type');
});
$: if (entered_passcode && entered_passcode.length >= 5) {
console.log(`entered_passcode=${entered_passcode}`);
handle_check_access_type_passcode();
}
$: if (trigger && $ae_loc.access_type) {
console.log(`$ae_loc.access_type=${$ae_loc.access_type}`);
let access_checks_results = ae_util.process_permission_checks($ae_loc.access_type);
$ae_loc = {...$ae_loc, ...access_checks_results};
} else if (trigger) {
console.log(`$ae_loc.access_type=not set`);
// Send an empty string to reset the permissions. This is the same as sending 'anonymous'.
let access_checks_results = ae_util.process_permission_checks('');
$ae_loc = {...$ae_loc, ...access_checks_results};
}
function handle_check_access_type_passcode() {
console.log(`*** handle_check_access_type_passcode() *** passcode list:`, $ae_loc.page_access_code_li);
if (entered_passcode && entered_passcode.length >= 5) {
if ($ae_loc.page_access_code_li.super == entered_passcode) {
console.log('Super passcode matched');
window.localStorage.setItem('access_type', 'super');
$ae_loc.access_type = 'super';
} else if ($ae_loc.page_access_code_li.manager == entered_passcode) {
console.log('Manager passcode matched');
window.localStorage.setItem('access_type', 'manager');
$ae_loc.access_type = 'manager';
} else if ($ae_loc.page_access_code_li.administrator == entered_passcode) {
console.log('Administrator passcode matched');
window.localStorage.setItem('access_type', 'administrator');
$ae_loc.access_type = 'administrator';
} else if ($ae_loc.page_access_code_li.trusted == entered_passcode) {
console.log('Trusted passcode matched');
window.localStorage.setItem('access_type', 'trusted');
$ae_loc.access_type = 'trusted';
} else if ($ae_loc.page_access_code_li.public == entered_passcode) {
console.log('Public passcode matched');
window.localStorage.setItem('access_type', 'public');
$ae_loc.access_type = 'public';
} else if ($ae_loc.page_access_code_li.authenticated == entered_passcode) {
console.log('Authenticated passcode matched');
window.localStorage.setItem('access_type', 'authenticated');
$ae_loc.access_type = 'authenticated';
} else {
console.log('Passcode does not match');
window.localStorage.setItem('access_type', 'anonymous');
$ae_loc.access_type = 'anonymous';
trigger = 'process_permission_check';
// $ae_loc = $ae_loc; // Trigger Svelte just in case
// ae_loc.set($ae_loc);
// console.log($ae_loc);
dispatch_access_type_changed();
return false;
}
entered_passcode = null;
trigger = 'process_permission_check';
// WARNING 2024-08-21: For some reason the config element does not auto show or hide when the access type changes.
if (!$ae_loc.iframe && $ae_loc.authenticated_access) {
$ae_loc.hub.show_element__access_type = true;
$ae_loc.hub.show_element__cfg = true;
} else if ($ae_loc.iframe && $ae_loc.trusted_access) {
$ae_loc.hub.show_element__access_type = true;
$ae_loc.hub.show_element__cfg = true;
} else {
$ae_loc.hub.show_element__access_type = true;
$ae_loc.hub.show_element__cfg = false;
}
dispatch_access_type_changed();
return true;
} else {
console.log('Entered passcode too short.');
// $ae_loc.access_type = null; // 'anonymous';
// dispatch_access_type_changed()
return null;
}
}
function handle_clear_access() {
// NOTE: I think it makes since to reset this to anonymous even if logged in as an admin or similar.
window.localStorage.setItem('access_type', 'anonymous');
// $ae_loc.access_type = null; // 'anonymous';
$ae_loc.access_type = 'anonymous';
trigger = 'process_permission_check';
show_passcode_input = false;
// $ae_loc = $ae_loc; // Trigger Svelte just in case
// ae_loc.set($ae_loc);
// console.log($ae_loc);
dispatch_access_type_changed();
return true;
}
function dispatch_access_type_changed() {
console.log('*** dispatch_access_type_changed() ***');
console.log(ae_util);
console.log($ae_loc);
dispatch('access_type_changed', {
access_type: $ae_loc.access_type
});
}
function dispatch_edit_mode_changed() {
console.log('*** dispatch_edit_mode_changed() ***');
console.log(ae_util);
console.log($ae_loc);
window.localStorage.setItem('edit_mode', $ae_loc.edit_mode);
dispatch('edit_mode_changed', {
edit_mode: $ae_loc.edit_mode
});
}
</script>
<section id="AE-Quick-Access-Type" class="ae_access_type bg-surface-100 text-surface-800 transition duration-300 delay-150 hover:delay-1000 hover:ease-out transition-all hover:transition-all hidden-print flex flex-col items-end gap-1">
<!-- Show list of authorized sessions and presentations for a user -->
<!-- {#if $ae_loc.access_type == 'administrator'}
{#if $events_loc.auth__kv.session}
Sessions:
<ul>
{#each Object.entries($events_loc.auth__kv.session) as [key, value]}
<li><a href="/events_pres_mgmt/session/{key}">
{key}
</a></li>
{/each}
</ul>
{/if}
{/if} -->
<div>
{#if $ae_loc.trusted_access}
{#if $ae_loc.edit_mode}
<button
on:click={() => {
$ae_loc.edit_mode = false;
dispatch_edit_mode_changed();
}}
class="btn btn-sm variant-ghost-success hover:variant-filled-success"
>
<span class="fas fa-toggle-on mx-1"></span>
Edit Mode On
</button>
{:else}
<button
on:click={() => {
$ae_loc.edit_mode = true;
dispatch_edit_mode_changed();
}}
class="btn btn-sm variant-ghost-warning hover:variant-filled-warning"
>
<span class="fas fa-toggle-off mx-1"></span>
Edit Mode?
</button>
{/if}
{/if}
</div>
<div>
{#if $ae_loc.access_type && $ae_loc.access_type != 'anonymous'}
<span class="fas fa-unlock mx-1"></span>
{#if $ae_loc.access_type == 'super'}
<span class="fas fa-hat-wizard m-1"></span>
Super
{:else if $ae_loc.access_type == 'manager'}
<span class="fas fa-user-shield m-1"></span>
Manager
{:else if $ae_loc.access_type == 'administrator'}
<span class="fas fa-user-ninja m-1"></span>
Administrator
{:else if $ae_loc.access_type == 'trusted'}
<span class="fas fa-user-check m-1"></span>
Trusted Access
{:else if $ae_loc.access_type == 'public'}
Public Access
{:else if $ae_loc.access_type == 'authenticated'}
Authenticated Access
{:else if $ae_loc.access_type == 'anonymous'}
Anonymous Access
{:else}
Unknown Access
{/if}
<button
class="btn btn-sm variant-ghost-success hover:variant-filled-success access_type_lock_btn transition-all hover:transition-all"
on:click={() => {
handle_clear_access();
}}
title="Access mode is currently enabled/unlocked. Click to exit and lock."
>
<span class="fas fa-lock mx-1"></span> Lock?
</button>
{:else}
<button
class="btn btn-sm variant-glass-success hover:variant-filled-warning access_type_unlock_btn transition-all hover:transition-all"
on:click={async () => {
show_passcode_input = !show_passcode_input;
await tick();
document.getElementById('access_passcode_input').focus();
// element.focus({preventScroll:false});
}}
title="Anonymous public access is currently set. Access mode is disabled/locked."
>
<span class="fas fa-lock mx-1 lock_icon"></span>
<span class="fas fa-unlock mx-1 unlock_icon hidden"></span>
<span class="unlock_text">Unlock?</span>
</button>
<input
id="access_passcode_input"
bind:value={entered_passcode}
class="input w-32 transition-all"
class:hidden={!show_passcode_input}
type="text"
placeholder="Access code"
/>
<!-- <div class="current_text transition-all">{$ae_loc.access_type}</div> -->
{/if}
</div>
</section>
<style lang="postcss">
/* BEGIN: AE's Svelte Quick Access Type component */
#AE-Quick-Access-Type {
/* position: absolute; */
position: fixed;
/* position: relative; */
/* position: static; */
/* position: sticky; */
/* top: 1em; */
bottom: 1.5rem;
right: 0rem;
padding: .5rem;
/* lightyellow */
/* background-color: hsla(60,100%,90%,.30); */
/* background-color: rgba(var(--color-surface-500) / .5); */
border-top: solid thin hsla(0,0%,0%,.25);
border-left: solid thin hsla(0,0%,0%,.25);
border-bottom: solid thin hsla(0,0%,0%,.25);
border-top-left-radius: .5em;
border-bottom-left-radius: .5em;
opacity: .15;
/* opacity: 1; */
font-size: .75rem;
z-index: 5;
/* NOTE: transition when no longer hovering */
transition-property: opacity, background-color;
transition-delay: 1.25s;
transition-duration: .75s;
transition-timing-function: ease-out;
}
#AE-Quick-Access-Type:hover {
/* lightyellow */
/* background-color: hsla(60,100%,90%,.95); */
/* background-color: rgba(var(--color-surface-500) / 1); */
border-top: solid thin hsla(0,0%,0%,.95);
border-left: solid thin hsla(0,0%,0%,.95);
border-bottom: solid thin hsla(0,0%,0%,.95);
opacity: 1;
/* NOTE: transition when hover starts */
transition-property: opacity, background-color;
transition-delay: .5s;
transition-duration: .25s;
transition-timing-function: ease-in;
}
/* #Access-Type .unlock_text {
transition: width 2s, height 2s, background-color 2s, transform 2s;
} */
/* END: Svelte Access Type component */
.access_type_unlock_btn:hover .lock_icon {
display: none;
}
.access_type_unlock_btn:hover .unlock_icon {
display: initial;
}
.access_type_unlock_btn .unlock_text {
display: none;
}
.access_type_unlock_btn:hover .unlock_text {
display: initial;
/* outline: solid thin red; */
}
.ae_access_type .current_text {
display: none;
}
.ae_access_type:hover .current_text {
display: initial;
/* outline: solid thin red; */
}
</style>

View File

@@ -0,0 +1,466 @@
<script lang="ts">
// *** Import Svelte core
import { createEventDispatcher, onMount } from 'svelte';
// *** Import Aether core variables and functions
import type { key_val } from '$lib/ae_stores';
// import { api } from '$lib/api';
import { core_func } from '$lib/ae_core_functions';
// import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
// *** Import Aether core components
// *** Import Aether module variables and functions
// *** Import Aether module components
// *** Export/Exposed variables and functions for component
export let log_lvl: number = 0;
export let trigger_patch: any = null;
export let api_cfg: key_val = {'api_crud_super_key': null};
// export let api_crud_super_key: null|string = api_cfg.api_crud_super_key;
export let object_type: string;
export let object_id: string;
export let field_name: string;
export let field_type: string = 'text'; // button, text, textarea, template (older method), select (in progress method)
export let field_value: any;
export let allow_null: boolean = false;
export let select_option_li: key_val = {};
export let val_empty_is_null: boolean = false; // This was added to help with a select option list. If the value is empty (''), it will be set to null.
export let edit_label: string = 'Edit';
export let display_inline: boolean = false;
export let display_block_edit: boolean = false;
export let textarea_cols: number = 80;
export let textarea_rows: number = 5;
// export let input_field_template: null|object = null;
export let hide_edit_btn = false;
export let outline_element = false;
export let show_crud = false;
export let btn_label = null; // '<span class="fas fa-check mx-1"></span> Save'; // PATCH
// export let show_field_name = true;
// export let show_original_value = true;
// export let trim_string = false;
// export let remove_breaks = false;
export let class_li: string = '';
// *** Set initial variables
let ae_promises: key_val = {}; // Promise<any>;
let patch_result: null|Promise<any>|key_val|string;
let original_field_value = field_value;
const dispatch = createEventDispatcher();
onMount(() => {
if (log_lvl) {
console.log(`Element AE CRUD: Object Type: ${object_type}; Object ID: ${object_id}; Field Name: ${field_name}; Field Value: ${field_value} (Original: ${original_field_value})`);
// ; Super Key: ${api_crud_super_key}
}
});
$: if (trigger_patch == true) {
console.log('AE CRUD: Patch triggered!');
trigger_patch = null;
handle_obj_field_patch(field_value);
}
// Updated 2024-03-22
async function handle_obj_field_patch(new_field_value: any) {
console.log('*** handle_obj_field_patch() ***');
patch_result = null;
// This was added to help with a select option list. If the value is empty (''), it will be set to null.
if (val_empty_is_null && new_field_value == '') {
new_field_value = null;
}
// NOTE: Is this needed? The field_name, field_value, and fields parameters for update_ae_obj_id_crud() already take care of the data portion. They are added to data_list object as part of the JSON request.
// NOTE: Currently this only handles one field and value at a time. This may need to be changed in the future to use the "fields" parameter as well.
// let patch_data = {}
// if (remove_breaks) {
// patch_data['field_value'] = field_value.replace(/(\r\n|\n|\r)/gm, "");
// } else {
// patch_data['field_value'] = field_value;
// }
// patch_data[field_name] = field_value;
// console.log(patch_data);
// let params = {};
ae_promises.api_update__ae_obj = core_func.handle_update_ae_obj_id_crud({
api_cfg: api_cfg,
object_type: object_type,
object_id: object_id,
field_name: field_name,
new_field_value: new_field_value,
params: {},
try_cache: false,
log_lvl: 0
})
.then(function (results) {
console.log('Field PATCH Promise', results);
if (results) {
console.log(`Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}; Original Field Value: ${original_field_value}`);
patch_result = 'PATCH complete';
original_field_value = new_field_value;
} else {
console.log(`Not Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}; Original Field Value: ${original_field_value}`);
patch_result = 'PATCH failed';
return false;
}
return true;
})
.catch(function (error) {
console.log('Something went wrong patching the record.');
console.log(error);
return false;
})
.finally(function () {
console.log('Field PATCH Promise finally');
// This dispatch() must be under "finally".
dispatch(
'ae_crud_updated',
{
'type': object_type,
'id': object_id,
'field_name': field_name,
'field_value': new_field_value,
'original_value': original_field_value,
}
);
});
return ae_promises.api_update__ae_obj;
}
</script>
<div
class="{class_li} ae_crud"
class:show_crud
class:display_inline
class:outline_element
>
<span class="field_viewing_wrapper">
<slot></slot>
<button
class="btn btn-sm variant-soft-warning hover:variant-ghost-error field_show_btn"
class:hide_edit_btn
class:show_crud
on:dblclick={() => {
show_crud = true;
}}
title="Double click to edit"
>
<span class="fas fa-edit"></span>
</button>
</span>
<div
class:display_block_edit
class="field_editing_wrapper min-w-content w-100 max-w-full"
>
<!-- <span class="grow flex flex-row items-center justify-between"> -->
<!-- <span class="">
{edit_label}
</span> -->
<button
class="btn btn-md variant-glass-tertiary hover:variant-ghost-tertiary m-1 transition-all"
class:show_crud
on:click={() => {
show_crud = false;
}}
title="Close field editing"
>
<span class="fas fa-window-close"></span>
<span class="hidden md:inline">Close</span>
</button>
<!-- </span> -->
<span
class="field_value grow min-w-content max-w-full"
class:show_crud
>
{#if field_type == 'template'}
<!-- <Element_input_v2 {...input_field_template} bind:value={field_value} /> -->
{:else if field_type == 'button'}
<!-- <input type="button" bind:value={field_value}> -->
{field_value}
{:else if field_type == 'select'}
<select
bind:value={field_value}
class="select"
>
{#if select_option_li && Object.keys(select_option_li).length == 0}
<option value="">-- not set --</option>
{:else if select_option_li && Object.keys(select_option_li).length > 0}
{#each Object.keys(select_option_li) as option}
<option value={option}>{select_option_li[option]}</option>
{/each}
{:else}
<option value="">-- no list --</option>
{/if}
</select>
{:else if field_type == 'text'}
<input
bind:value={field_value}
class="input min-w-64 w-96 max-w-full"
>
{:else if field_type == 'textarea'}
<textarea
bind:value={field_value}
cols={textarea_cols}
rows={textarea_rows}
class="textarea"
></textarea>
{:else}
<input
bind:value={field_value}
class="input w-fit"
>
{/if}
{#if allow_null}
<button
class="btn btn-sm variant-soft-warning hover:variant-ghost-warning m-1"
on:click={() => {
field_value = null;
}}
title="Set value to NULL"
>
&Oslash;
NULL
</button>
{/if}
</span>
<button
class="btn btn-lg variant-glass-primary hover:variant-ghost-primary m-1"
class:show_crud
disabled={field_value == original_field_value}
on:click={async () => {
handle_obj_field_patch(field_value);
}}
title="Save new field value"
>
{#if field_value == original_field_value}
{#if (btn_label)}
{@html btn_label}
{:else}
<span class="fas fa-check mx-1"></span>
<span>Save</span>
{/if}
<!-- <span>{patch_result}</span> -->
{:else}
{#if (btn_label)}
{@html btn_label}
{:else}
<span class="fas fa-save mx-1"></span>
<span>Save?</span>
{/if}
{/if}
</button>
<div class="field_patch_result" class:show_crud>
{#await ae_promises.api_update__ae_obj}
<span class="fas fa-spinner fa-spin mx-1"></span>
<span>Processing...</span>
{:then}
{#if patch_result}
<span class="fas fa-check mx-1"></span>
<span>{patch_result}</span>
{:else}
<!-- <div>Nothing to show yet...</div> -->
{/if}
{/await}
</div>
</div>
</div>
<style>
/* .ae_crud .field_editing_wrapper {
font-size: 1em;
} */
/* BEGIN: Svelte CRUD (update) component */
/* .ae_crud {
margin: 0;
padding: 0;
} */
.ae_crud.display_inline {
/* outline: solid thin red; */
display: inline;
}
.ae_crud.show_crud .field_viewing_wrapper .field_show_btn {
display: none;
}
.ae_crud.outline_element .field_viewing_wrapper {
outline: dotted thin hsla(0,50%,50%,0);
transition: outline 3s 1s;
}
.ae_crud.outline_element .field_viewing_wrapper:hover {
outline: dashed thin hsla(0,50%,50%,.9);
transition: outline 1s .5s;
}
.ae_crud .field_viewing_wrapper .field_show_btn.hide_edit_btn {
display: none;
}
.ae_crud .field_viewing_wrapper .field_show_btn {
margin: 0;
padding: 0;
/* color: hsla(0,0%,50%,.8); */
opacity: .25;
/* NOTE: transition when hover ends */
transition-property: opacity, background-color, border-color, color, height, width;
transition-delay: 1.00s; /* no delay */
transition-duration: .55s;
transition-timing-function: linear;
}
.ae_crud .field_viewing_wrapper:hover .field_show_btn {
/* outline: solid thin hsla(0,50%,50%,.9); */
/* color: hsla(0,50%,50%,.9); */
opacity: 1;
/* NOTE: transition when hover starts */
transition-property: opacity, background-color, border-color, color, height, width;
transition-delay: .25s; /* no delay */
transition-duration: .50s;
transition-timing-function: linear;
}
.ae_crud .field_editing_wrapper {
/* outline: dashed thin pink; */
display: none;
/* position: relative; */
/* contain: layout; */
/* contain: size; */
/* contain: none; */
contain: content;
box-shadow: .5em .5em .75em .75em hsla(0,0%,0%,0.5);
/* color: hsla(0,0%,50%,.8); */
background-color: hsla(0,0%,50%,.5);
border: dashed thin transparent;
/* font-size: 1em; */
/* line-height: 1em; */
height: 1em;
width: 1em;
/* NOTE: transition when hover ends */
transition-property: background-color, border-color, color, height, width;
transition-delay: .75s; /* short delay */
transition-duration: .50s;
transition-timing-function: linear;
}
.ae_crud.show_crud .field_editing_wrapper {
/* display: initial; */
display: block;
contain: content;
/* background-color: yellow; */
background-color: hsla(60,50%,80%,.95);
border: solid thin hsla(0,50%,50%,.50);
border-radius: .5em;
height: auto;
/* height: 100%; */
max-height: 100%;
min-width: fit-content;
width: auto;
max-width: 100%;
/* NOTE: transition when hover starts */
transition-property: background-color, border-color, height, width;
transition-delay: .25s; /* no delay */
transition-duration: .25s;
transition-timing-function: linear;
/* position: absolute; */
/* position: fixed; */
/* position: relative; */
/* top: 1em; */
/* left: 1em; */
/* right: 1em; */
/* bottom: 1em; */
z-index: 1;
padding: .5em;
}
.ae_crud.show_crud.display_inline .field_editing_wrapper {
/* display: block; */
display: inline-block;
/* display: inline; */
box-shadow: initial;
background-color: hsla(60,50%,80%,.3);
padding: .25em;
position: initial;
z-index: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
gap: .5em;
width: 30%;
}
.ae_crud.show_crud.display_inline .field_editing_wrapper.display_block_edit {
/* display: block; */
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: .5em;
flex-grow: 1;
height: auto;
width: 100%;
}
.ae_crud textarea {
height: auto;
}
/* END: Svelte CRUD (update) component */
</style>

View File

@@ -0,0 +1,358 @@
<script lang="ts">
import { createEventDispatcher, onMount } from 'svelte';
import { RadioGroup, RadioItem } from '@skeletonlabs/skeleton';
import { ae_util } from '$lib/ae_utils';
import { ae_loc, ae_sess, ae_api, slct, slct_trigger } from '$lib/ae_stores';
let notes: null|string = null;
let all: boolean = false;
// export let theme_mode: null|string = null;
export let set_theme_mode: null|boolean = null;
// export let theme_name: null|string = null;
export let set_theme_name: null|boolean = null;
const dispatch = createEventDispatcher();
onMount(() => {
console.log('** Element Mounted: ** Element App Config');
if (set_theme_mode) {
$slct_trigger = 'set_theme_mode';
}
if (set_theme_name) {
$slct_trigger = 'set_theme_name';
}
});
// $: if ($slct_trigger == 'set_theme_mode' && $ae_loc?.hub?.theme_mode) {
// console.log(`$ae_loc.hub.theme_mode=${$ae_loc?.hub?.theme_mode}`);
// $slct_trigger = null;
// if ($ae_loc.hub.theme_mode == 'light') {
// document.documentElement.classList.remove('dark');
// document.documentElement.classList.add('light');
// } else if ($ae_loc.hub.theme_mode == 'dark') {
// document.documentElement.classList.remove('light');
// document.documentElement.classList.add('dark');
// }
// }
// $: if ($slct_trigger == 'set_theme_name' && $ae_loc?.hub?.theme_name) {
// console.log(`$ae_loc?.hub?.theme_name=${$ae_loc?.hub?.theme_name}`);
// $slct_trigger = null;
// // Update the body attribute named "data-theme" to the current theme name.
// document.body.setAttribute('data-theme', $ae_loc?.hub?.theme_name);
// }
// $: if (entered_passcode && entered_passcode.length >= 5) {
// console.log(`entered_passcode=${entered_passcode}`);
// handle_check_access_type_passcode();
// }
// $: if (trigger && $ae_loc.access_type) {
// console.log(`$ae_loc.access_type=${$ae_loc.access_type}`);
// let access_checks_results = ae_util.process_permission_checks($ae_loc.access_type);
// $ae_loc = {...$ae_loc, ...access_checks_results};
// } else if (trigger) {
// console.log(`$ae_loc.access_type=not set`);
// // Send an empty string to reset the permissions. This is the same as sending 'anonymous'.
// let access_checks_results = ae_util.process_permission_checks('');
// $ae_loc = {...$ae_loc, ...access_checks_results};
// }
function handle_something() {
// console.log('*** handle_something() ***');
}
function handle_clear_storage(item: null|string) {
// console.log('*** handle_clear_storage() ***');
// window.localStorage.setItem('access_type', 'anonymous');
// return true;
}
function dispatch_something_changed() {
console.log('*** dispatch_something_changed() ***');
console.log(ae_util);
console.log($ae_loc);
dispatch('access_type_changed', {
access_type: $ae_loc.access_type
});
}
</script>
<!-- transition duration-500 delay-1000 hover:duration-500 hover:delay-1000 hover:transition-all -->
<section id="AE-App-Cfg" class="ae_app_cfg bg-surface-100 text-surface-800 transition hover:transition-all hidden-print">
<div
class="ae_cfg_content text-xs space-y-4 my-4"
class:hidden={!$ae_loc.hub.show_element__cfg_detail}
data-sveltekit-preload-data="false"
>
<section class="space-y-2">
<div>
<h2 class="strong">Access Type:</h2>
<div>
{#if $ae_loc.access_type && $ae_loc.access_type != 'anonymous'}
{#if $ae_loc.access_type == 'super'}
<span class="fas fa-secret mx-1"></span> Super Access
{:else if $ae_loc.access_type == 'manager'}
<span class="fas fa-user-shield mx-1"></span> Manager Access
{:else if $ae_loc.access_type == 'administrator'}
<span class="fas fa-user-ninja mx-1"></span> Administrator Access
{:else if $ae_loc.access_type == 'trusted'}
<span class="fas fa-user-nurse mx-1"></span> Trusted Access
{:else if $ae_loc.access_type == 'authenticated'}
<span class="fas fa-user-friends mx-1"></span> Authenticated Access
{:else if $ae_loc.access_type == 'anonymous'}
<span class="fas fa-users mx-1"></span> Anonymous Access
{:else}
<span class="fas fa-unlock mx-1"></span> Unknown Access
{/if}
<!-- <button
class="btn btn-sm variant-glass-secondary access_type_lock_btn hover:transition-all"
on:click={() => {
handle_clear_access();
}}
title="Access mode is currently enabled/unlocked. Click to exit and lock."
>
<span class="fas fa-lock mx-1"></span> Lock
</button> -->
{:else}
Not logged in
{/if}
</section>
<!-- END: Access Type -->
<section class="space-y-2">
<h2 class="strong">Theme:</h2>
<div>
<!-- Light/Dark Theme: -->
<RadioGroup
active="variant-glass-success"
hover="hover:variant-ringed-surface"
>
<RadioItem
on:change={() => {
$slct_trigger = 'set_theme_mode';
}}
bind:group={$ae_loc.hub.theme_mode}
name="theme_light"
value={'light'}
>
Light
</RadioItem>
<RadioItem
on:change={() => {
$slct_trigger = 'set_theme_mode';
}}
bind:group={$ae_loc.hub.theme_mode}
name="theme_dark"
value={'dark'}
>
Dark
</RadioItem>
</RadioGroup>
</div>
<div>
<!-- Theme Name: -->
<select
on:change={() => {
$slct_trigger = 'set_theme_name';
}}
bind:value={$ae_loc.hub.theme_name}
class="select"
title="Theme name"
>
<option value="">-- None --</option>
<option value="gold-nouveau">Gold Nouveau</option>
<option value="hamlindigo">Hamlindigo</option>
<option value="modern">Modern</option>
<option value="rocket">Rocket</option>
<option value="wintry">Wintry</option>
</select>
</div>
</section>
<!-- END: Theme -->
<section class="space-y-2">
<h2 class="strong">Utilities:</h2>
<a
class="btn btn-sm variant-glass-secondary"
href="/hosted_files"
>
<span class="fas fa-code mx-1"></span>
Util: Convert Videos
</a>
{#if $ae_loc.iframe}
<a
class="btn btn-sm variant-glass-secondary"
href="/?iframe=false"
>
<span class="fas fa-code mx-1"></span>
Exit iframe Mode
</a>
{:else}
<a
class="btn btn-sm variant-glass-secondary"
href="/?iframe=true"
>
<span class="fas fa-code mx-1"></span>
Use iframe Mode
</a>
{/if}
<div>
<button
class="btn btn-sm variant-glass-warning"
title="Reload and clear the page cache"
on:click={() => {
// $ae_loc.
window.location.reload(true);
}}
>
<span class="fas fa-sync mx-1"></span>
Reload
&amp;
<span class="fas fa-trash mx-1"></span>
Clear Cache
</button>
<button
class="btn btn-sm variant-glass-warning"
title="Clear the browser storage for this page"
on:click={() => {
if (!confirm('Are you sure you want to clear the local and session storage?')) {
return false;
}
// Clear the local and session storage
localStorage.clear();
sessionStorage.clear();
// Clear Indexed DB as well
indexedDB.deleteDatabase('ae_core_db');
indexedDB.deleteDatabase('ae_events_db');
window.location.reload();
// alert('Local and Session Storage cleared and Indexed DBs deleted. You will probably want to refresh the page.');
}}
>
<span class="fas fa-eraser mx-1"></span>
Clear Storage &amp; DB
</button>
</div>
</section>
<!-- END: Utilities -->
</div>
<button
class="btn btn-sm variant-glass-warning ae_cfg_btn hover:transition-all"
on:click={() => {
$ae_loc.hub.show_element__cfg_detail = !$ae_loc.hub.show_element__cfg_detail;
}}
>
<span class="fas fa-cog mx-1"></span>
<span class="cfg_text">Config</span>
</button>
</section>
<style lang="postcss">
/* BEGIN: AE's Svelte App Config component */
#AE-App-Cfg {
/* position: absolute; */
position: fixed;
/* position: relative; */
/* position: static; */
/* position: sticky; */
/* top: 1em; */
bottom: 1.5rem;
left: 0rem;
padding: .5rem;
/* lightyellow */
/* background-color: hsla(60,100%,90%,.30); */
/* background-color: rgba(var(--color-surface-500) / .95); */
border-top: solid thin hsla(0,0%,0%,.5);
border-right: solid thin hsla(0,0%,0%,.5);
border-bottom: solid thin hsla(0,0%,0%,.5);
border-top-right-radius: .5em;
border-bottom-right-radius: .5em;
opacity: .15;
/* opacity: 1; */
font-size: .75rem;
z-index: 5;
/* NOTE: transition when no longer hovering */
transition-property: opacity, background-color;
transition-delay: 1.25s;
transition-duration: .5s;
transition-timing-function: ease-out;
}
#AE-App-Cfg:hover {
/* lightyellow */
/* background-color: hsla(60,100%,90%,.95); */
/* background-color: rgba(var(--color-surface-100) / 1); */
/* color: black; */
border-top: solid thin hsla(0,0%,0%,.95);
border-right: solid thin hsla(0,0%,0%,.95);
border-bottom: solid thin hsla(0,0%,0%,.95);
opacity: 1;
/* NOTE: transition when hover starts */
transition-property: opacity, background-color;
transition-delay: .5s;
transition-duration: .10s;
transition-timing-function: ease-in;
}
.ae_cfg_btn .cfg_text {
display: none;
}
.ae_cfg_btn:hover .cfg_text {
display: initial;
/* outline: solid thin red; */
}
.access_type .current_text {
display: none;
}
.access_type:hover .current_text {
display: initial;
/* outline: solid thin red; */
}
/* END: AE's Svelte App Config component */
</style>

View File

@@ -0,0 +1,807 @@
<script lang="ts">
import { onMount } from 'svelte';
// import type { Writable } from 'svelte/store';
// import { localStorageStore } from '@skeletonlabs/skeleton';
import { api } from '$lib/api';
import { ae_loc, ae_sess, ae_api, slct, slct_trigger, ae_trig } from '$lib/ae_stores';
import { ae_util } from '$lib/ae_utils';
import type { key_val } from '$lib/ae_stores';
export let expire_minutes: number = 10;
export let mount_reload_sec: number = 0;
export let ds_code: string;
export let ds_name: null|string = null;
export let ds_type: string = 'text';
export let for_type: null|string = null;
export let for_id: null|string = null;
console.log(`ae_e_data_store ${ds_code} for_type=${for_type} for_id=${for_id} account_id=${$ae_loc.account_id}`);
// export let store: string = 'local';
export let display: string = 'block'; // Avoid; Use class list instead
export let class_li: string = ''; // : string[] = [];
export let try_cache: boolean = true;
export let hide: boolean = false; // Hide the entire element
export let show_edit: boolean = false;
export let show_edit_btn: boolean = true;
export let show_view: boolean = true;
// export let show_delete_btn: boolean = false;
export let ds_loaded: boolean = false;
export let debug: boolean = false;
let ae_promises: key_val = {}; // Promise<any>;
let ds_get_results: Promise<any>|key_val;
let ds_loading_status: string = 'starting...';
let ds_submit_results: Promise<any>|key_val;
let val_json: key_val;
let val_html: key_val;
let val_md: key_val;
export let val_sql: null|key_val = null;
let val_text: string;
let ds_code_obj =
{
id: null,
account_id: null,
code: ds_code,
name: ds_name,
type: ds_type,
for_type: null, // for_type
for_id: null, // for_id
access_read: null, // 'super', 'manager', 'administrator', 'trusted', 'authenticated', 'anonymous'
access_write: null, // 'super', 'manager', 'administrator', 'trusted', 'authenticated', 'anonymous'
access_delete: null, // 'super', 'manager', 'administrator', 'trusted', 'authenticated', 'anonymous'
html: null,
json: null,
md: null,
text: null,
updated_on: null,
chk_account_id: null,
};
let ae_ds_tmp: key_val;
if (browser && localStorage.getItem(`ae_ds__${ds_code}`)) {
ae_ds_tmp = JSON.parse(localStorage.getItem(`ae_ds__${ds_code}`));
} else {
ae_ds_tmp = ds_code_obj;
}
// Writable<key_val> = localStorageStore(`ae_ds__${ds_code}`, ds_code_obj);
// console.log(`ae_e_data_store cached: ${ds_code} = `, ae_ds_tmp);
console.log(`ae_e_data_store cached: ${ds_code} account_id=${$ae_loc.account_id}`);
if (!ae_ds_tmp || !ae_ds_tmp.id) {
ds_loading_status = '-- loading --';
} else {
// ae_ds_loc.set(ae_ds_tmp);
}
$ae_sess.ds.submit_status = null;
$ae_sess.ds.create_status = null;
$ae_sess.ds.update_status = null;
let trigger: null|string = null;
// $: if (ae_ds_tmp) {
// console.log(`ae_e_data_store ae_ds_loc = `, ae_ds_tmp);
// }
import { browser } from '$app/environment';
let ae_ds_loc_test: any;
if (browser) {
console.log('ae_e_data_store Browser detected.');
ae_ds_loc_test = JSON.parse(localStorage.getItem(`ae_ds__${ds_code}`));
console.log(`ae_e_data_store ae_ds_loc_test = `, ae_ds_loc_test);
// ae_ds_tmp = {id: null};
// ae_ds_tmp = ae_ds_loc_test;
} else {
console.log('ae_e_data_store Browser not detected.');
}
// This is a quick check to make sure the data store is not stale. If it is, then we need to trigger a reload.
if (browser && ae_ds_tmp && ae_ds_tmp.loaded_on && ae_ds_tmp.chk_account_id == $ae_loc.account_id) {
console.log(`ae_e_data_store ${ds_code} loaded_on: ${ae_ds_tmp.loaded_on}`);
let loaded_on = new Date(ae_ds_tmp.loaded_on);
let now = new Date();
let diff = now.getTime() - loaded_on.getTime();
let diff_minutes = diff / (1000 * 60);
if (diff_minutes > expire_minutes) {
console.log(`ae_e_data_store: Data Store ${ds_code} stale. Last loaded on: ${loaded_on.toISOString()}`);
// Wait for random number of milliseconds to avoid all data stores being reloaded at the same time.
let random_ms = Math.floor(Math.random() * 500);
console.log(`ae_e_data_store: Random number of milliseconds: ${random_ms}`);
setTimeout(() => {
trigger = 'load__ds__code';
}, random_ms);
}
} else if (browser) {
console.log('ae_e_data_store: No loaded_on date found and or the account_id check failed. Need to trigger reload.');
trigger = 'load__ds__code';
}
// This is a secondary check... The account_id should either be null or match the current account_id.
if (!ae_ds_tmp || !ae_ds_tmp.account_id === null || $ae_loc.account_id == $ae_loc.account_id) {
trigger = 'load__ds__code';
}
onMount(() => {
console.log('Element: Data Store element_data_store.svelte');
// console.log('ae_ MOUNTED Browser detected.');
if (mount_reload_sec) {
// Wait for random number of milliseconds to avoid all data stores being reloaded at the same time.
let random_ms = Math.floor(Math.random() * mount_reload_sec * 1000);
console.log(`ae_e_data_store: Random number of milliseconds: ${random_ms}`);
setTimeout(() => {
trigger = 'load__ds__code';
}, random_ms);
}
});
// let ds_code_li = {}; //: key_val; // = ae_loc_tmp.ds;
// console.log(`ae_ ds_code_li = `, ds_code_li);
$: if (trigger == 'load__ds__code' && ds_code && ds_type) {
console.log(`ae_e_data_store: ae_ load__ds__code: ${ds_code} ds_type=${ds_type} for_type=${for_type} for_id=${for_id} ${try_cache}`);
trigger = null;
load_data_store({
code: ds_code,
type: ds_type,
for_type: for_type,
for_id: for_id,
try_cache: try_cache
});
}
async function load_data_store(
{
code,
type='text',
for_type=null,
for_id=null,
try_cache=true
}: {
code: string,
type: string,
for_type: string|null,
for_id: string|null,
try_cache: boolean
}
) {
// let ds_code_val = await api.get_data_store_obj_w_code({
ds_get_results = api.get_data_store_obj_w_code({
api_cfg: $ae_api,
data_store_code: code,
data_type: type,
log_lvl: 0
})
.then( function (ds_results) {
// console.log(`ae_ Data Store ${code} = `, ds_results);
if (ds_results) {
console.log(`ae_e_data_store: Got a result for code ${code}`);
if (!ds_results.data_store_id_random) {
console.log('Something went wrong? No data store ID found.');
return false;
}
ds_loaded = true;
// Set the loaded_on datetime to the current time for reference later. This will be used to determine if the data store is stale.
ae_ds_tmp.loaded_on = new Date().toISOString();
// Set the chk_account_id as a backup check to make sure the data store belongs to the account for the current site. This should not be needed, but here we are...
ae_ds_tmp.chk_account_id = $ae_loc.account_id;
ae_ds_tmp.id = ds_results.data_store_id_random;
ae_ds_tmp.account_id = ds_results.account_id_random;
ae_ds_tmp.code = ds_results.code; // This will overwrite whatever was passed in.
ae_ds_tmp.name = ds_results.name;
ae_ds_tmp.type = ds_results.type; // This will overwrite whatever was passed in.
if (type == 'html') {
ae_ds_tmp.html = ds_results.text;
val_html = ds_results.text;
return ds_results.html;
} else if (type == 'json') {
ae_ds_tmp.json = ds_results.json;
val_json = ds_results.json;
return ds_results.json;
} else if (type == 'md') {
ae_ds_tmp.text = ds_results.text;
val_md = ds_results.text;
return ds_results.text;
} else if (type == 'sql') {
ae_ds_tmp.text = ds_results.text;
val_sql = ds_results.text;
return ds_results.text;
} else {
ae_ds_tmp.text = ds_results.text;
val_text = ds_results.text;
return ds_results.text;
}
} else {
ds_loaded = false;
ds_loading_status = '-- not found --';
}
})
.catch(function (error) {
console.log(`Something went wrong. for code ${code}`);
console.log(error);
ds_loading_status = '-- error --';
return false;
});
// .finally(function (ds_val_result) {
// // console.log(`ae_ ds_code_val = `, ds_val_result);
// // ae_ds_loc.set(ds_val_result);
// // localStorage.setItem(ds_code, ds_val_result);
// // sessionStorage.setItem(ds_code, ds_val_result);
// // return ds_val_result;
// });
// console.log(`ae_ ds_code_val = `, ds_code_val);
}
async function handle_submit_form(event: any) {
// console.log('*** handle_submit_form() ***');
$ae_sess.ds.submit_status = 'processing';
// Data in
let form_data = new FormData(event.target);
// console.log(form_data);
let data_store_di: key_val = ae_util.extract_prefixed_form_data({prefix: null, form_data: form_data, trim_values: true, bool_tf_str: true, log_lvl: 0});
// console.log(data_store_di);
// Data out
let data_store_do: key_val = {};
if (typeof data_store_di.ds_id_random !== 'undefined') {
data_store_do['data_store_id_random'] = data_store_di.ds_id_random;
}
// if (!$slct.data_store_id) {
if (!ae_ds_tmp.id) {
data_store_do['account_id_random'] = $ae_loc.account_id;
}
if (typeof data_store_di.ds_account_id !== 'undefined' && data_store_di.ds_account_id && data_store_di.ds_use_account_id) {
data_store_do['account_id_random'] = data_store_di.ds_account_id;
} else if (data_store_di.ds_use_account_id && $ae_loc.account_id) {
data_store_do['account_id_random'] = $ae_loc.account_id;
} else {
data_store_do['account_id_random'] = null;
}
if (typeof data_store_di.ds_code !== 'undefined') {
data_store_do['code'] = data_store_di.ds_code;
} else {
data_store_do['code'] = ds_code;
}
if (typeof data_store_di.ds_name !== 'undefined') {
data_store_do['name'] = data_store_di.ds_name;
} else {
data_store_do['name'] = ds_name;
}
if (typeof data_store_di.ds_type !== 'undefined') {
data_store_do['type'] = data_store_di.ds_type;
} else {
data_store_do['type'] = ds_type;
}
if (typeof data_store_di.ds_for_type !== 'undefined' && data_store_di.ds_for_type) {
data_store_do['for_type'] = data_store_di.ds_for_type;
} else {
data_store_do['for_type'] = null;
}
if (typeof data_store_di.ds_for_id !== 'undefined' && data_store_di.ds_for_id) {
data_store_do['for_id_random'] = data_store_di.ds_for_id;
} else {
data_store_do['for_id_random'] = null;
}
if (typeof data_store_di.ds_access_read !== 'undefined') {
data_store_do['access_read'] = data_store_di.ds_access_read;
}
if (typeof data_store_di.ds_access_write !== 'undefined') {
data_store_do['access_write'] = data_store_di.ds_access_write;
}
if (typeof data_store_di.ds_access_delete !== 'undefined') {
data_store_do['access_delete'] = data_store_di.ds_access_delete;
}
if (typeof data_store_di.ds_value !== 'undefined') {
if (data_store_di.ds_type == 'html') {
data_store_do['text'] = data_store_di.ds_value;
} else if (data_store_di.ds_type == 'json') {
data_store_do['json'] = data_store_di.ds_value;
} else if (data_store_di.ds_type == 'md') {
data_store_do['text'] = data_store_di.ds_value;
} else if (data_store_di.ds_type == 'sql') {
data_store_do['text'] = data_store_di.ds_value;
} else {
data_store_do['text'] = data_store_di.ds_value;
}
}
if (typeof data_store_di.ds_enable !== 'undefined') {
data_store_do['enable'] = data_store_di.ds_enable;
} else {
data_store_do['enable'] = true;
}
console.log(data_store_do);
if (!ae_ds_tmp.id) {
// Create
console.log(`ae_ Data Store Create:`, data_store_do);
ds_submit_results = handle_create__data_store({
obj_type: 'data_store',
data: data_store_do
})
.then( function (ds_results) {
console.log(`ae_ Data Store Create Results:`, ds_results);
if (ds_results) {
ae_ds_tmp.id = ds_results.data_store_id_random;
ae_ds_tmp.updated_on = ds_results.updated_on;
}
return ds_results;
})
.finally(function (ds_val_result) {
console.log(`ae_ ds_val_result = `, ds_val_result);
trigger = 'load__ds__code';
$ae_sess.ds.submit_status = 'created';
});
} else {
// Update
console.log(`ae_ Data Store Update:`, data_store_do);
ds_submit_results = handle_update__data_store({
obj_type: 'data_store',
obj_id: ae_ds_tmp.id,
data: data_store_do
})
.then( function (ds_results) {
console.log(`ae_ Data Store Update Results:`, ds_results);
if (ds_results) {
ae_ds_tmp.updated_on = ds_results.updated_on;
}
return ds_results;
// })
// .finally(function (ds_val_result) {
// // console.log(`ae_ ds_code_val = `, ds_val_result);
})
.finally(function () {
// console.log(`ae_ ds_val_result = `, ds_val_result);
console.log(`ae_ load__ds__code: ${ds_code} ${ds_type} ${for_type} ${for_id} ${try_cache}`);
trigger = 'load__ds__code';
$ae_sess.ds.submit_status = 'updated';
});
}
}
async function handle_create__data_store({
obj_type,
data
}) {
console.log('*** handle_create__data_store() ***');
$ae_sess.ds.create_status = 'starting';
ae_promises.api_create__data_store_obj = api.create_ae_obj_crud({
api_cfg: $ae_api,
obj_type: obj_type,
fields: data,
key: $ae_api.api_crud_super_key,
log_lvl: 1
})
.then(async function (create__obj_result) {
if (!create__obj_result) {
console.log('The result was null or false.');
return false;
}
return create__obj_result;
})
.catch(function (error) {
console.log('Something went wrong.');
console.log(error);
return false;
})
.finally(function (create__obj_result) {
$ae_sess.ds.create_status = 'finished';
return create__obj_result;
});
return ae_promises.api_create__data_store_obj;
}
async function handle_update__data_store({
obj_type,
obj_id,
data
}) {
console.log('*** handle_update__data_store() ***');
$ae_sess.ds.update_status = 'starting';
ae_promises.update__data_store_obj = api.update_ae_obj_id_crud({
api_cfg: $ae_api,
obj_type: obj_type,
obj_id: obj_id,
fields: data,
key: $ae_api.api_crud_super_key,
log_lvl: 1
})
.then(async function (update__obj_result) {
if (!update__obj_result) {
console.log('The result was null or false.');
return false;
}
return update__obj_result;
})
.catch(function (error) {
console.log('Something went wrong.');
console.log(error);
return false;
})
.finally(function (update__obj_result) {
$ae_sess.ds.update_status = 'finished';
return update__obj_result;
})
return ae_promises.update__data_store_obj;
}
</script>
<div
class="ae__elem__data_store relative {class_li}"
class:hide={hide}
>
{#if ae_ds_tmp}
{#if debug || $ae_loc.debug == 'debug'}
<pre>
id: {ae_ds_tmp.id},
code: {ae_ds_tmp.code},
type: {ae_ds_tmp.type},
for_type: {ae_ds_tmp.for_type},
for_id: {ae_ds_tmp.for_id},
access_read: {ae_ds_tmp.access_read},
access_write: {ae_ds_tmp.access_write},
access_delete: {ae_ds_tmp.access_delete},
name: {ae_ds_tmp.name},
html: {ae_ds_tmp.html},
json: {ae_ds_tmp.json},
md: {ae_ds_tmp.md},
text: {ae_ds_tmp.text},
updated_on: {ae_ds_tmp.updated_on},
</pre>
{/if}
{#if show_edit}
<section class="edit z-50">
<form
class="ae__elem__data_store__form"
on:submit|preventDefault={handle_submit_form}
>
<input
type="hidden"
name="ds_id_random"
value={ae_ds_tmp.id}
/>
{#if $ae_loc.trusted_access}
<label for="ds_use_account_id" class="label text-xs inline">Use Account ID
<input
type="checkbox"
name="ds_use_account_id"
class="checkbox"
value="true"
checked={ae_ds_tmp.account_id ? true : false}
/>
</label>
{/if}
{#if $ae_loc.manager_access}
<input
type="text"
name="ds_account_id"
class="input max-w-48 text-xs"
placeholder="Account ID"
value={ae_ds_tmp.account_id}
/>
<input
type="text"
name="ds_code"
class="input text-xs"
placeholder="Data store code"
value={ae_ds_tmp.code}
required
/>
{/if}
{#if $ae_loc.trusted_access}
<input
type="text"
name="ds_name"
class="input text-xs"
placeholder="Data store name"
value={ae_ds_tmp.name}
required
/>
{/if}
{#if $ae_loc.manager_access}
<input
type="text"
name="ds_type"
class="input max-w-48 text-xs"
placeholder="Data store type (html, json, md, sql, text)"
value={ae_ds_tmp.type}
required
/>
<input
type="text"
name="ds_for_type"
class="input max-w-48 text-xs"
placeholder="Data store For Type"
value={ae_ds_tmp.for_type}
/>
<input
type="text"
name="ds_for_id"
class="input max-w-48 text-xs"
placeholder="Data store For ID"
value={ae_ds_tmp.for_id}
/>
<input
type="text"
name="ds_access_read"
class="input max-w-48 text-xs"
placeholder="Access read"
value={ae_ds_tmp.access_read}
/>
<input
type="text"
name="ds_access_write"
class="input max-w-48 text-xs"
placeholder="Access write"
value={ae_ds_tmp.access_write}
/>
<input
type="text"
name="ds_access_delete"
class="input max-w-48 text-xs"
placeholder="Access delete"
value={ae_ds_tmp.access_delete}
/>
{:else}
Code: {ae_ds_tmp.code}
<!-- Name: {ae_ds_tmp.name} -->
Type: {ae_ds_tmp.type}
{/if}
<!-- Handle HTML type -->
{#if ae_ds_tmp.type == 'html' || ae_ds_tmp.type == null}
<textarea
name="ds_value"
class="textarea type_html font-mono text-sm"
cols="75"
rows="25"
placeholder="Enter the HTML here"
>{ae_ds_tmp.type == 'html' && ae_ds_tmp.html ? ae_ds_tmp.html : ''}</textarea>
<!-- Handle SQL type -->
{:else if ae_ds_tmp.type == 'sql'}
<textarea
name="ds_value"
class="textarea type_sql font-mono text-sm"
cols="75"
rows="25"
placeholder="Enter the SQL here"
>{ae_ds_tmp.type == 'sql' && ae_ds_tmp.text ? ae_ds_tmp.text : ''}</textarea>
<!-- Handle text type -->
{:else if ae_ds_tmp.type == 'text'}
<textarea
name="ds_value"
class="textarea type_text"
cols="70"
rows="10"
placeholder="Enter the text here"
>{ae_ds_tmp.type == 'text' ? ae_ds_tmp.text : ''}</textarea>
{/if}
<div class="flex gap-1 justify-center justify-evenly items-center p-1">
<button
type="button"
class="btn variant-soft-warning"
on:click={() => {
if (confirm('Are you sure you want to delete this data store?')) {
trigger = 'delete__ds__code';
// $slct_trigger = 'delete__ds__code';
}
show_edit = false;
show_view = true;
}}
>
<span class="fas fa-trash mx-1"></span>
Delete
</button>
<button
type="button"
class="btn variant-soft-primary"
on:click={() => {
show_edit = false;
show_view = true;
}}
>
<span class="fas fa-times mx-1"></span>
Close
</button>
<button
type="submit"
class="btn variant-soft-primary"
disabled={ds_submit_results instanceof Promise && !ds_submit_results}
on:click={() => {
trigger = 'save__ds__code';
// $slct_trigger = 'save__ds__code';
}}
>
<span class="fas fa-save mx-1"></span>
Save
</button>
{#await ds_submit_results}
<div class="modal-loading">
<span class="fas fa-spinner fa-spin"></span>
<span class="loading-text">
Saving...
</span>
</div>
{:then ds_submit_results}
{#if ds_submit_results}
<div>
<span class="fas fa-check text-green-500"></span>
<span class="saved-text">
Saved
</span>
</div>
{/if}
{/await}
<div
class="ae_debug"
class:hidden={!debug && $ae_loc.debug != 'debug'}
>
submit: {$ae_sess.ds.submit_status}
create: {$ae_sess.ds.create_status}
update: {$ae_sess.ds.update_status}
</div>
</div>
</form>
</section>
{/if}
<!-- {#if mode == 'view'} -->
{#if !ae_ds_tmp.type && !ae_ds_tmp.html && !ae_ds_tmp.json && !ae_ds_tmp.md && !ae_ds_tmp.text}
{#if $ae_loc.manager_access}
<span class="variant-soft-warning">No data found! Is the data store correct or new?</span>
{:else}
<!-- <span class="variant-soft">loading</span> -->
{/if}
{/if}
{#if ae_ds_tmp.type == 'html' && ae_ds_tmp.html}
{@html ae_ds_tmp.html}
{:else if ae_ds_tmp.type == 'html'}
{#if $ae_loc.manager_access}
<span class="variant-soft-warning">No HTML found! Is the data store type correct?</span>
{:else}
<!-- <span class="variant-soft">loading</span> -->
{/if}
{/if}
{#if ae_ds_tmp.type == 'text' && ae_ds_tmp.text}
{ae_ds_tmp.text}
{:else if ae_ds_tmp.type == 'text'}
{#if $ae_loc.manager_access}
<span class="variant-soft-warning">No text found! Is the data store type correct?</span>
{:else}
<!-- <span class="variant-soft">loading</span> -->
{/if}
{/if}
<button
type="button"
class="ae_btn_edit__ds btn hover:variant-glass-warning text-xs absolute top-0 right-0 opacity-30 hover:opacity-100 transition delay-700 hover:delay-200 m-1 p-1"
class:opacity-5={!$ae_loc.manager_access}
class:hidden={!show_edit_btn || !$ae_loc.trusted_access}
on:dblclick={() => {
trigger = 'load__ds__code';
show_edit = true;
show_view = false;
}}
title="Double click to edit data store: {ds_code} with {ae_ds_tmp.account_id ? `account ID=${ae_ds_tmp.account_id}` : 'no account ID'}"
>
<span class="fas fa-edit mx-1"></span>
Edit
</button>
<!-- {/if} -->
{:else}
<!-- Nothing to see yet -->
{/if}
<!-- Text:
<pre>
{val_text}
</pre> -->
<!-- JSON:
<pre>
{val_json}
</pre> -->
{#await ds_get_results}
<div class="modal-loading text-xs absolute bottom-0 left-0 opacity-30 hover:opacity-100 transition delay-700 hover:delay-200">
<span class="fas fa-spinner fa-spin"></span>
<span class="loading-text">
Loading...
</span>
</div>
{/await}
<!-- {ds_loading_status} -->
</div>
<style lang="postcss">
/* .ae_btn_edit__ds {
opacity: .5;
} */
/* The section.edit should be above the rest of the content and centered on the page */
section.edit {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 100;
background-color: hsla(0, 0%, 100%, .95);
padding: 1rem;
border-radius: .5rem;
box-shadow: 0 0 1rem hsla(0, 0%, 0%, .5);
min-width: 80%;
}
.hide {
display: none;
}
</style>

View File

@@ -0,0 +1,413 @@
<script lang="ts">
import { createEventDispatcher, onMount, tick } from 'svelte';
import type { key_val } from '$lib/ae_stores';
import { ae_util } from '$lib/ae_utils';
// import { api } from '$lib/api';
import { core_func } from '$lib/ae_core_functions';
import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
export let element_id = 'svelte_input_file_element';
export let input_name = 'file_list';
export let container_class_li: string[] = [];
export let input_class_li: string[] = ['file_drop_area'];
export let table_class_li: string[] = ['table', 'table-sm', 'table-striped', 'table-hover' , 'text-sm'];
export let multiple: boolean = true;
export let required: boolean = true;
export let accept: string = 'audio/*, image/*, video/*, .bak, .cfg, .css, .csv, .doc, .docx, .gz, .htm, .html, .ini, .iso, .j2, .json, .key, .keynote, .md, .pdf, .ppt, .pptx, .rar, .rtf, .sql, .svelte, ttf, .txt, .xls, .xlsx, .xz, .zip, .bin, .dmg, .exe, .js, .msi, .php, .py, .sh';
export let untrusted_extension_list = ['bin', 'dmg', 'exe', 'js', 'msi', 'php', 'py', 'sh'];
export let legacy_extension_list = ['avi', 'doc', 'ppt', 'xls', 'wmv'];
export let use_selected_file_table = true;
export let file_list_status: null|string = null;
export let processed_file_list: any[] = [];
const dispatch = createEventDispatcher();
export let input_file_list: any = null;
let input_file_list_processed: any[] = [];
onMount(() => {
console.log('** Element Mounted: ** Element Input File');
});
$: if (input_file_list) {
console.log(input_file_list);
process_file_list(input_file_list)
.then(function (result) {
// console.log(result);
if (!result || !result.length) {
file_list_status = 'none';
}
// Save the results to the file upload list to be displayed as a table.
input_file_list_processed = result; // Includes file hash
dispatch(
'input_file_list_updated',
{
element_id: element_id,
input_file_list: input_file_list,
input_file_list_processed: result, // Includes file hash
}
);
});
}
async function process_file_list(file_list) {
console.log('*** process_file_list() ***');
file_list_status = 'processing';
processed_file_list = [];
if (!file_list) {
// file_list_processed = null;
file_list_status = 'none';
// await tick();
return processed_file_list;
}
// const forLoop = async _ => {
// console.log('*** Start ***');
// for (let [i, file_item] of file_list.entries()) { // Not sure why this does not work???
for await (const [i, file_item] of Array.prototype.entries.call(file_list)) {
console.log(i, file_item);
// NOTE: The file list is readonly. The filenames can not be changed here.
if (file_item.name.endsWith('.odpmac') || file_item.name.endsWith('.odpwin') || file_item.name.endsWith('.pptmac') || file_item.name.endsWith('.pptwin') || file_item.name.endsWith('.pptxmac') || file_item.name.endsWith('.pptxwin')) {
console.log('This file extension may need to be fixed? API upload will take care of it.');
// file_item.name = file_item.name.replace('.odpwin', '.odp');
}
let file_data: key_val = {};
let filename = file_item.name;
// console.log(filename);
file_data['filename'] = filename;
let guessed_extension = ae_util.guess_file_extension(filename);
file_data['guessed_extension'] = guessed_extension;
file_data['type'] = file_item.type;
let modified_date = new Date(file_item.lastModified);
file_data['modified_date'] = modified_date;
let modified_datetime_string = ae_util.iso_datetime_formatter(modified_date, 'datetime_medium');
file_data['modified_datetime_string'] = modified_datetime_string;
let file_size_bytes = file_item.size;
file_data['file_size_bytes'] = file_size_bytes;
let file_size_string = ae_util.format_bytes(file_item.size, 2);
file_data['file_size_string'] = file_size_string;
// // NOTE: Calculate the hash of the file before upload. Check if this exact file has already been uploaded.
// let file_reader = new FileReader();
// file_reader.onload = async function() {
// const hash_buffer = crypto.subtle.digest('SHA-256', file_reader.result);
// let hash_hex_test = hash_buffer.then(async function (result_buffer) {
// const hash_array = Array.from(new Uint8Array(result_buffer)); // convert buffer to byte array
// const hash_hex = hash_array.map(b => b.toString(16).padStart(2, '0')).join('');
// console.log(`File hash hex? ${hash_hex}`);
// file_data['hash_sha256'] = hash_hex;
// return hash_hex;
// })
// .catch(function (error) {
// console.log('Something went wrong?', error);
// });
// return hash_hex_test;
// // file_data['hash_hex_test'] = hash_hex_test;
// // const hash_buffer = await crypto.subtle.digest('SHA-256', file_reader.result);
// // let hash_str = await new TextDecoder().decode(hash_buffer);
// // console.log(`File hash string? ${hash_str}`);
// // file_data['hash_str'] = hash_str;
// // const hash_array = Array.from(new Uint8Array(hash_buffer)); // convert buffer to byte array
// // const hash_hex = hash_array.map(b => b.toString(16).padStart(2, '0')).join('');
// // console.log(`File hash hex? ${hash_hex}`);
// // file_data['hash_sha256'] = hash_hex;
// // return hash_hex_test;
// // return hash_hex;
// }
// // file_reader.then(function (result) {
// // console.log(`File hash hex? ${result}`);
// // return hash_hex;
// // })
// // .catch(function (error) {
// // console.log('No results returned or failed.', error);
// // });
// // file_data['hash_sha256'] = file_reader.readAsArrayBuffer(file_item);
let warning_untrusted_extension = false;
let warning_legacy_extension = false;
let warning_size = false;
let warning_message = null;
if (untrusted_extension_list.includes(guessed_extension)) {
console.log('This is an untrusted extension. Going to warn.')
warning_untrusted_extension = true;
warning_message = 'It appears this an untrusted file type and is likely meant to be an executable or installable application. It is <strong>strongly</strong> recommended that this file not be used.';
} else if (legacy_extension_list.includes(guessed_extension)) {
console.log('This is a legacy extension. Going to warn.')
warning_legacy_extension = true;
if (guessed_extension == 'ppt') {
warning_message = 'It appears this is a legacy PowerPoint file and has not been officially supported since Office PowerPoint 2003. This file is known to have issues and may not work well. It is <strong>strongly</strong> recommended that this file be saved using the modern PPTX format.';
} else if (guessed_extension == 'avi') {
warning_message = 'It appears this is a video file using the AVI format. It is <strong>strongly</strong> recommended that this file be re-saved as an MP4, MOV, MKV, or MPG/MPEG. The file will also likely be much smaller.';
} else if (guessed_extension == 'wmv') {
warning_message = 'It appears this is a video file using Microsoft\'s WMV format. It is <strong>strongly</strong> recommended that this file be re-saved as an MP4, MOV, MKV, or MPG/MPEG.';
} else {
warning_message = 'It appears this is a legacy or not very well supported file format. It is <strong>strongly</strong> recommended that it be saved in an alternative format if possible.';
}
} else if (file_size_bytes > 52428800) {
// 50 MB = 52428800 bytes
// 100 MB = 104857600 bytes
console.log(`This is a large file size ${file_size_bytes / 1048576} MB (${file_size_bytes} bytes). Going to warn.`);
warning_size = true;
if (file_size_bytes > 2147483648) { // > 2 GB
warning_message = `This file size (${file_size_string}) is very large and will take at <strong>least</strong> a few minutes to upload depending on your network connection. In some cases it may be worth compressing the file or embedded media. Most audio, image, and video files can be compressed without a significant loss in quality. Be sure you have a stable network connection, especially if you are uploading over a wireless connection. Many business (convention centers, hotels, restaurants, etc) cap upload speeds significantly.`;
} else if (file_size_bytes > 209715200) { // > 200 MB
warning_message = `This file size (${file_size_string}) is large and will likely take at <strong>least</strong> a few minutes to upload depending on your network connection. Be sure you have a stable network connection, especially if you are uploading over a wireless connection. Many business (convention centers, hotels, restaurants, etc) cap upload speeds significantly. In some cases it may be worth compressing the file or embedded media. Many audio, image, and video files can be compressed without a significant loss in quality.`;
} else if (file_size_bytes > 104857600) { // 100 MB to 200 MB
warning_message = `This file size (${file_size_string}) is large and will likely take a few minutes to upload depending on your network connection. Be sure you have a stable network connection. In some cases it may be worth compressing the file or embedded media. Many audio, image, and video files can be compressed without a significant loss in quality.`;
} else { // 50 to 100 MB
warning_message = `This file size (${file_size_string}) is large and may take a few minutes to upload depending on your network connection. In some cases it may be worth compressing the file or embedded media. Many audio, image, and video files can be compressed without a significant loss in quality.`;
}
} else {
}
file_data['warning_untrusted_extension'] = warning_untrusted_extension;
file_data['warning_legacy_extension'] = warning_legacy_extension;
file_data['warning_size'] = warning_size;
file_data['warning_message'] = warning_message;
file_data['uploaded'] = null;
file_data['uploaded_bytes'] = null;
// input_file_list_processed.push(JSON.parse(JSON.stringify(file_data)));
// input_file_list_processed = input_file_list_processed;
// console.log(get_file_hash(file_item));
// console.log(await get_file_hash(file_item));
let file_hash = null;
// Only hash files less than 2 GB (2147483648 bytes)!!!
console.log(`File size: ${file_size_bytes / 1048576} MB (${file_size_bytes} bytes)`);
if (file_size_bytes < 2000000000) { // > 2 GB 2 147 483 648
file_hash = await ae_util.get_file_hash(file_item);
} else {
// File size in MB
console.log(`File is too large to hash. File size: ${file_size_bytes / 1048576} MB`);
}
if (file_hash) {
console.log(`Found file hash to lookup: ${ae_util.shorten_string({string: file_hash})}`);
file_data['hash_sha256'] = file_hash;
let check_hosted_file_obj_w_hash_result = await core_func.check_hosted_file_obj_w_hash({
api_cfg: $ae_api,
hosted_file_hash: file_hash
});
// console.log(check_hosted_file_obj_w_hash_result);
if (check_hosted_file_obj_w_hash_result && check_hosted_file_obj_w_hash_result.hosted_file_found_check) {
console.log('Matching hash!!!');
file_data['hash_sha256_match'] = true;
// $ae_events.pres_mgmt.new_upload_list[i].hash_sha256_match = true;
// $ae_events = $ae_events;
}
} else {
file_data['hash_sha256'] = null;
file_data['hash_sha256_match'] = false;
}
processed_file_list.push(file_data);
// input_file_list_processed.push(file_data);
}
file_list_status = 'ready';
console.log(processed_file_list);
// return JSON.parse(JSON.stringify(processed_file_list));
return processed_file_list
}
function remove_file_from_filelist(index) {
console.log('*** remove_file_from_filelist() ***');
// Can not use something like this because it is readonly:
const dt = new DataTransfer();
// let input = document.getElementById(input_element_id);
let input_element = document.querySelector('input[type="file"].svelte_input_file_element');
if (!input_element) {
console.error('Could not find the input element.');
return false;
}
let files = input_file_list;
if (!files || !files.length) {
console.error('No files found in the file list.');
file_list_status = null;
return false;
}
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (index !== i) // Only include the file if it does not match the index value.
dt.items.add(file);
}
// NOTE: I thought just setting the input_element.files OR input_file_list would trigger the input_file_list change.
// input_element.files = Object.assign({}, dt.files);
input_element.files = dt.files; // Assign the updates list
// input_file_list = null;
input_file_list = dt.files; // I feel like this should not need to be done, but doing it anyways.
return true;
}
</script>
<div class="svelte_element ae_element ae_input_file flex flex-col gap-1 items-center justify-center {container_class_li.join(' ')} text-center">
<label
for={element_id}
class="svelte_input_file_label text-center"
>
<div>
<span class="fas fa-upload"></span>
<!-- Select files to upload -->
<!-- <span class="fas fa-file-archive"></span> -->
<strong>Upload your files</strong>
<!-- (drag and drop) -->
</div>
<span>
Presentation related files only<br>
(PowerPoint, Keynote, PDF, mp4, Word Doc, Excel, txt, etc)
</span>
</label>
<input
id={element_id}
type="file"
bind:files={input_file_list}
{multiple}
{required}
{accept}
name={input_name}
class="svelte_input_file_element {input_class_li.join(' ')}"
/>
{#if file_list_status == 'processing'}
<div class="file_list_status ae_warning variant-ghost-warning p-1 m-1">
<span class="fas fa-spinner fa-spin m-1"></span> Processing selected file list...
</div>
{/if}
<!-- {#await input_file_list_processed} -->
<!-- {:then} -->
{#if use_selected_file_table && input_file_list_processed && input_file_list_processed.length}
<strong>Files selected for upload</strong>
<table class="slct_file_list text-sm {table_class_li.join(' ')}">
<thead>
<tr>
<th>Remove</th>
<th>Filename</th>
<th>Modified</th>
<th>Size</th>
<!-- <th>Type</th> -->
<th>Ext</th>
<th>Hash</th>
</tr>
</thead>
{#each input_file_list_processed as file_list_item, file_index}
<tbody>
<tr>
<td class="file_remove">
<button
on:click|preventDefault={() => { (remove_file_from_filelist(file_index)); }}
class="btn btn-md variant-soft-warning hover:variant-filled-secondary m-1"
title="Remove file from upload list">
<span class="fas fa-minus"></span>
</button>
</td>
<td class="file_filename">{file_list_item.filename}</td>
<td class="file_last_modified">{file_list_item.modified_datetime_string}</td>
<td
class="file_size"
class:bg-pink-200={file_list_item.warning_size}
>
{file_list_item.file_size_string}
<!-- {#if $ae_sess.api_upload_kv[link_to_id]}
<span class="text-xs">({$ae_sess.api_upload_kv[link_to_id].percent_completed}%)</span>
{/if} -->
</td>
<!-- <td class="file_type" class:warning_file_untrusted_extension={file_list_item.warning_untrusted_extension} class:warning_file_legacy_extension={file_list_item.warning_legacy_extension}>{file_list_item.type}</td> -->
<td
class="file_extension"
class:bg-red-200={file_list_item.warning_untrusted_extension}
class:bg-pink-200={file_list_item.warning_legacy_extension}
>
{file_list_item.guessed_extension}
</td>
<td
class="file_hash file_hash256"
class:bg-pink-200={file_list_item.hash_sha256_match}
>
{ae_util.shorten_string({string: file_list_item.hash_sha256, begin_length: 5, end_length: 4, wildcard_length: 2})}
</td>
</tr>
</tbody>
{/each}
</table>
{/if}
</div>
<style>
th {
text-align: center;
/* font-size: smaller; */
}
td {
text-align: center;
}
.file_last_modified {
font-size: smaller;
}
.file_size, .file_type {
/* font-size: smaller; */
}
.file_hash {
font-family: 'Courier New', Courier, monospace;
}
</style>

View File

@@ -0,0 +1,386 @@
<script lang="ts">
import { createEventDispatcher, onMount, tick } from 'svelte';
import type { key_val } from '$lib/ae_stores';
import { ae_util } from '$lib/ae_utils';
// import { api } from '$lib/api';
import { core_func } from '$lib/ae_core_functions';
import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
// export let element_id = 'svelte_input_file_element';
export let container_class_li: string[] = [];
export let table_class_li: string[] = ['table', 'table-sm', 'table-striped', 'table-hover' , 'text-sm'];
export let untrusted_extension_list = ['bin', 'dmg', 'exe', 'js', 'msi', 'php', 'py', 'sh'];
export let legacy_extension_list = ['avi', 'doc', 'ppt', 'xls', 'wmv'];
export let use_selected_file_table = true;
export let input_file_list: any = null;
export let file_list_status: null|string = null;
export let processed_file_list: any[] = [];
// const dispatch = createEventDispatcher();
// let input_file_list_processed: any[] = [];
onMount(() => {
console.log('** Element Mounted: ** Element Input File');
});
$: if (input_file_list) {
console.log(input_file_list);
process_file_list(input_file_list)
.then(function (result) {
// console.log(result);
if (!result || !result.length) {
processed_file_list = [];
file_list_status = 'none';
}
// Save the results to the file upload list to be displayed as a table.
// input_file_list_processed = result; // Includes file hash
// dispatch(
// 'input_file_list_updated',
// {
// element_id: element_id,
// input_file_list: input_file_list,
// input_file_list_processed: result, // Includes file hash
// }
// );
});
} else {
processed_file_list = [];
file_list_status = 'none';
}
async function process_file_list(file_list) {
console.log('*** process_file_list() ***');
file_list_status = 'processing';
processed_file_list = [];
if (!file_list) {
// file_list_processed = null;
file_list_status = 'none';
// await tick();
return processed_file_list;
}
// const forLoop = async _ => {
// console.log('*** Start ***');
// for (let [i, file_item] of file_list.entries()) { // Not sure why this does not work???
for await (const [i, file_item] of Array.prototype.entries.call(file_list)) {
console.log(i, file_item);
// NOTE: The file list is readonly. The filenames can not be changed here.
if (file_item.name.endsWith('.odpmac') || file_item.name.endsWith('.odpwin') || file_item.name.endsWith('.pptmac') || file_item.name.endsWith('.pptwin') || file_item.name.endsWith('.pptxmac') || file_item.name.endsWith('.pptxwin')) {
console.log('This file extension may need to be fixed? API upload will take care of it.');
// file_item.name = file_item.name.replace('.odpwin', '.odp');
}
let file_data: key_val = {};
let filename = file_item.name;
// console.log(filename);
file_data['filename'] = filename;
let guessed_extension = ae_util.guess_file_extension(filename);
file_data['guessed_extension'] = guessed_extension;
file_data['type'] = file_item.type;
let modified_date = new Date(file_item.lastModified);
file_data['modified_date'] = modified_date;
let modified_datetime_string = ae_util.iso_datetime_formatter(modified_date, 'datetime_medium');
file_data['modified_datetime_string'] = modified_datetime_string;
let file_size_bytes = file_item.size;
file_data['file_size_bytes'] = file_size_bytes;
let file_size_string = ae_util.format_bytes(file_item.size, 2);
file_data['file_size_string'] = file_size_string;
// // NOTE: Calculate the hash of the file before upload. Check if this exact file has already been uploaded.
// let file_reader = new FileReader();
// file_reader.onload = async function() {
// const hash_buffer = crypto.subtle.digest('SHA-256', file_reader.result);
// let hash_hex_test = hash_buffer.then(async function (result_buffer) {
// const hash_array = Array.from(new Uint8Array(result_buffer)); // convert buffer to byte array
// const hash_hex = hash_array.map(b => b.toString(16).padStart(2, '0')).join('');
// console.log(`File hash hex? ${hash_hex}`);
// file_data['hash_sha256'] = hash_hex;
// return hash_hex;
// })
// .catch(function (error) {
// console.log('Something went wrong?', error);
// });
// return hash_hex_test;
// // file_data['hash_hex_test'] = hash_hex_test;
// // const hash_buffer = await crypto.subtle.digest('SHA-256', file_reader.result);
// // let hash_str = await new TextDecoder().decode(hash_buffer);
// // console.log(`File hash string? ${hash_str}`);
// // file_data['hash_str'] = hash_str;
// // const hash_array = Array.from(new Uint8Array(hash_buffer)); // convert buffer to byte array
// // const hash_hex = hash_array.map(b => b.toString(16).padStart(2, '0')).join('');
// // console.log(`File hash hex? ${hash_hex}`);
// // file_data['hash_sha256'] = hash_hex;
// // return hash_hex_test;
// // return hash_hex;
// }
// // file_reader.then(function (result) {
// // console.log(`File hash hex? ${result}`);
// // return hash_hex;
// // })
// // .catch(function (error) {
// // console.log('No results returned or failed.', error);
// // });
// // file_data['hash_sha256'] = file_reader.readAsArrayBuffer(file_item);
let warning_untrusted_extension = false;
let warning_legacy_extension = false;
let warning_size = false;
let warning_message = null;
if (untrusted_extension_list.includes(guessed_extension)) {
console.log('This is an untrusted extension. Going to warn.')
warning_untrusted_extension = true;
warning_message = 'It appears this an untrusted file type and is likely meant to be an executable or installable application. It is <strong>strongly</strong> recommended that this file not be used.';
} else if (legacy_extension_list.includes(guessed_extension)) {
console.log('This is a legacy extension. Going to warn.')
warning_legacy_extension = true;
if (guessed_extension == 'ppt') {
warning_message = 'It appears this is a legacy PowerPoint file and has not been officially supported since Office PowerPoint 2003. This file is known to have issues and may not work well. It is <strong>strongly</strong> recommended that this file be saved using the modern PPTX format.';
} else if (guessed_extension == 'avi') {
warning_message = 'It appears this is a video file using the AVI format. It is <strong>strongly</strong> recommended that this file be re-saved as an MP4, MOV, MKV, or MPG/MPEG. The file will also likely be much smaller.';
} else if (guessed_extension == 'wmv') {
warning_message = 'It appears this is a video file using Microsoft\'s WMV format. It is <strong>strongly</strong> recommended that this file be re-saved as an MP4, MOV, MKV, or MPG/MPEG.';
} else {
warning_message = 'It appears this is a legacy or not very well supported file format. It is <strong>strongly</strong> recommended that it be saved in an alternative format if possible.';
}
} else if (file_size_bytes > 52428800) {
// 50 MB = 52428800 bytes
// 100 MB = 104857600 bytes
console.log(`This is a large file size ${file_size_bytes / 1048576} MB (${file_size_bytes} bytes). Going to warn.`);
warning_size = true;
if (file_size_bytes > 2147483648) { // > 2 GB
warning_message = `This file size (${file_size_string}) is very large and will take at <strong>least</strong> a few minutes to upload depending on your network connection. In some cases it may be worth compressing the file or embedded media. Most audio, image, and video files can be compressed without a significant loss in quality. Be sure you have a stable network connection, especially if you are uploading over a wireless connection. Many business (convention centers, hotels, restaurants, etc) cap upload speeds significantly.`;
} else if (file_size_bytes > 209715200) { // > 200 MB
warning_message = `This file size (${file_size_string}) is large and will likely take at <strong>least</strong> a few minutes to upload depending on your network connection. Be sure you have a stable network connection, especially if you are uploading over a wireless connection. Many business (convention centers, hotels, restaurants, etc) cap upload speeds significantly. In some cases it may be worth compressing the file or embedded media. Many audio, image, and video files can be compressed without a significant loss in quality.`;
} else if (file_size_bytes > 104857600) { // 100 MB to 200 MB
warning_message = `This file size (${file_size_string}) is large and will likely take a few minutes to upload depending on your network connection. Be sure you have a stable network connection. In some cases it may be worth compressing the file or embedded media. Many audio, image, and video files can be compressed without a significant loss in quality.`;
} else { // 50 to 100 MB
warning_message = `This file size (${file_size_string}) is large and may take a few minutes to upload depending on your network connection. In some cases it may be worth compressing the file or embedded media. Many audio, image, and video files can be compressed without a significant loss in quality.`;
}
} else {
}
file_data['warning_untrusted_extension'] = warning_untrusted_extension;
file_data['warning_legacy_extension'] = warning_legacy_extension;
file_data['warning_size'] = warning_size;
file_data['warning_message'] = warning_message;
file_data['uploaded'] = null;
file_data['uploaded_bytes'] = null;
// input_file_list_processed.push(JSON.parse(JSON.stringify(file_data)));
// input_file_list_processed = input_file_list_processed;
// console.log(get_file_hash(file_item));
// console.log(await get_file_hash(file_item));
let file_hash = null;
// Only hash files less than 2 GB (2147483648 bytes)!!!
console.log(`File size: ${file_size_bytes / 1048576} MB (${file_size_bytes} bytes)`);
if (file_size_bytes < 2000000000) { // > 2 GB 2 147 483 648
file_hash = await ae_util.get_file_hash(file_item);
} else {
// File size in MB
console.log(`File is too large to hash. File size: ${file_size_bytes / 1048576} MB`);
}
if (file_hash) {
console.log(`Found file hash to lookup: ${ae_util.shorten_string({string: file_hash})}`);
file_data['hash_sha256'] = file_hash;
let check_hosted_file_obj_w_hash_result = await core_func.check_hosted_file_obj_w_hash({
api_cfg: $ae_api,
hosted_file_hash: file_hash
});
// console.log(check_hosted_file_obj_w_hash_result);
if (check_hosted_file_obj_w_hash_result && check_hosted_file_obj_w_hash_result.hosted_file_found_check) {
console.log('Matching hash!!!');
file_data['hash_sha256_match'] = true;
// $ae_events.pres_mgmt.new_upload_list[i].hash_sha256_match = true;
// $ae_events = $ae_events;
}
} else {
file_data['hash_sha256'] = null;
file_data['hash_sha256_match'] = false;
}
processed_file_list.push(file_data);
// input_file_list_processed.push(file_data);
}
file_list_status = 'ready';
console.log(processed_file_list);
// return JSON.parse(JSON.stringify(processed_file_list));
return processed_file_list
}
function remove_file_from_filelist(index) {
console.log('*** remove_file_from_filelist() ***');
// Can not use something like this because it is readonly:
const dt = new DataTransfer();
// let input = document.getElementById(input_element_id);
let input_element = document.querySelector('input[type="file"].svelte_input_file_element');
if (!input_element) {
console.error('Could not find the input element.');
return false;
}
let files = input_file_list;
if (!files || !files.length) {
console.error('No files found in the file list.');
file_list_status = null;
return false;
}
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (index !== i) // Only include the file if it does not match the index value.
dt.items.add(file);
}
// NOTE: I thought just setting the input_element.files OR input_file_list would trigger the input_file_list change.
// input_element.files = Object.assign({}, dt.files);
input_element.files = dt.files; // Assign the updates list
// input_file_list = null;
input_file_list = dt.files; // I feel like this should not need to be done, but doing it anyways.
return true;
}
</script>
<div class="svelte_element ae_element ae_input_file flex flex-col gap-1 items-center justify-center {container_class_li.join(' ')} text-center">
{#if file_list_status == 'processing'}
<div class="file_list_status ae_warning variant-ghost-warning p-1 m-1">
<span class="fas fa-spinner fa-spin m-1"></span> Processing selected file list...
</div>
{/if}
<!-- {#await processed_file_list} -->
<!-- {:then} -->
{#if use_selected_file_table && processed_file_list && processed_file_list.length}
<strong>Files selected for upload</strong>
<table class="slct_file_list text-sm {table_class_li.join(' ')}">
<thead>
<tr>
<th>Remove</th>
<th>Filename</th>
<th>Modified</th>
<th>Size</th>
<!-- <th>Type</th> -->
<th>Ext</th>
<th>Hash</th>
</tr>
</thead>
{#each processed_file_list as file_list_item, file_index}
<tbody>
<tr>
<td class="file_remove">
<button
on:click|preventDefault={() => { (remove_file_from_filelist(file_index)); }}
class="btn btn-md variant-soft-warning hover:variant-filled-secondary m-1"
title="Remove file from upload list">
<span class="fas fa-minus"></span>
</button>
</td>
<td class="file_filename">{file_list_item.filename}</td>
<td class="file_last_modified">{file_list_item.modified_datetime_string}</td>
<td
class="file_size"
class:bg-pink-200={file_list_item.warning_size}
>
{file_list_item.file_size_string}
{#if $ae_sess.api_upload_kv[file_list_item.hash_sha256]}
<span class="text-xs">({$ae_sess.api_upload_kv[file_list_item.hash_sha256].percent_completed}%)</span>
{/if}
</td>
<!-- <td class="file_type" class:warning_file_untrusted_extension={file_list_item.warning_untrusted_extension} class:warning_file_legacy_extension={file_list_item.warning_legacy_extension}>{file_list_item.type}</td> -->
<td
class="file_extension"
class:bg-red-200={file_list_item.warning_untrusted_extension}
class:bg-pink-200={file_list_item.warning_legacy_extension}
>
{file_list_item.guessed_extension}
</td>
<td
class="file_hash file_hash256"
class:bg-pink-200={file_list_item.hash_sha256_match}
>
{ae_util.shorten_string({string: file_list_item.hash_sha256, begin_length: 5, end_length: 4, wildcard_length: 2})}
</td>
</tr>
</tbody>
{/each}
</table>
{/if}
</div>
<style>
th {
text-align: center;
/* font-size: smaller; */
}
td {
text-align: center;
}
.file_last_modified {
font-size: smaller;
}
.file_size, .file_type {
/* font-size: smaller; */
}
.file_hash {
font-family: 'Courier New', Courier, monospace;
}
</style>

View File

@@ -0,0 +1,574 @@
<script lang="ts">
import { createEventDispatcher, onMount } from 'svelte';
import util from './utilities.js';
// import Select_element_lu from './element_select_lu.svelte';
/* *** BEGIN *** Core input settings */
export let id_random: string = ''; // OSIT Aether specific
export let obj_type: string = ''; // OSIT Aether specific
export let obj_prop_name: string = ''; // OSIT Aether specific
export let use_name_prefix: boolean = false;
export let name: string = (use_name_prefix ? `${obj_type}__${obj_prop_name}` : obj_prop_name);
// console.log(name);
export let id: string = `${obj_type}__${obj_prop_name}--${id_random}`; // Same as the value for "for"
// console.log(id);
export let value: null|boolean|number|string = null; // The current value of the property
console.log(`Input name=${name} value=${value}`);
export let default_value: null|boolean|number|string = null; // The default value for when value is ''
// console.log('Default Value:', default_value);
export let original_value: null|boolean|number|string = value; // The original value
console.log('Original Value', original_value);
export let data_type: string = typeof value; // boolean, number, string, json
console.log('Data Type:', data_type);
// hidden, text, email, date, number, select, checkbox, radio, textarea, etc
export let type: string = 'text'; // Input type
let set_input_type = (node) => {
node.type = 'text';
};
let input_element_type_list = ['checkbox', 'date', 'email', 'hidden', 'number', 'text'];
if (input_element_type_list.includes(type)) {
set_input_type = (node) => {
node.type = type;
};
} else {
}
console.log(`Input name=${name} value=${value} type=${type}`);
export let disabled: boolean = false; // attribute format: disabled
export let readonly: boolean = false; // attribute format: readonly="readonly"
export let required: boolean = false; // attribute format: required="required"
export let pattern: null|string = null;
export let focus: boolean = false;
/* *** END *** Core input settings */
/* *** BEGIN *** Container content, layout, and behavior */
// Input element specific label and placeholder
export let label: string = '';
export let label_date: string = 'Date';
export let label_time: string = 'Time';
export let placeholder: string = label;
// Input description for container
export let description: string = ''; // Description
// Layout and style
export let content_layout: string = ''; // Default empty is label wrap first, label_start, label_end, floating_input
export let class_li: string[] = []; // Classes for the input element
export let style: string = ''; // Style for the input element
export let display: string = ''; // Default empty is inline. inline, block, inline-block, break (break after)
export let label_class_li: string[] = [];
export let label_style: string = '';
export let label_display: string = ''; // Default empty is inline. inline, block, inline-block, break (break after)
export let label_location: string = 'start'; // start, end
export let description_location: string = 'end'; // start, end
export let container_class_li: string[] = []; // Classes for the container element
export let container_style: string = '';
export let container_display: string = ''; // Default empty is div block. inline, block, inline-block, break (break after)
export let multipart_class_li: string[] = [];
export let input_mode: null|string = null; // This is for special/custom modes like a rich text editor or search.
console.log(`Input input_mode=${input_mode}`);
/* *** END *** Container content, layout, and behavior */
/* *** BEGIN *** Input type specific */
// For checkbox, radio, and select option
export let option_li: any[] = []; // For checkbox, radio, and select inputs. Not specific to select options. List of key value pairs.
export let option_none: boolean = false; // If set to true then it will add an option using the select_option_none_text value
export let option_none_text: string = '-- Not Selected --'; // If set to true then it will add an option using the select_option_none_text value
// For textarea
export let size: number = null;
export let rows: number = 3;
export let cols: number = 80;
if (type == 'textarea') {
console.log(`Input textarea size=${size} rows=${rows} cols=${cols}`);
}
// For custom date_time. Not "date" or "time" input type only.
export let date_time_tz: null|string = null;
let value_datetime = null;
let value_date = null;
let value_time = null;
if (type == 'date_time' && value) {
console.log(`date_time value: ${value}`);
value_datetime = new Date(value+'Z'); // Append the Z so it knows it is UTC (YYY-MM-DDTHH:mm:ssZ)
console.log(value_datetime);
value_datetime = util.iso_datetime_formatter(value_datetime,'datetime_iso');
value_date = util.iso_datetime_formatter(value_datetime,'date_iso');
value_time = util.iso_datetime_formatter(value_datetime,'time_iso');
// value_date = value_datetime.toLocaleDateString();
// value_date = value_datetime.toISOString();
// value_time = value_datetime.toLocaleTimeString();
// value_time = value_datetime.toISOString();
} else if (type == 'date_time') {
console.log('No datetime value passed');
}
if (type == 'date_time') {
console.log(`Input date_time value_datetime=${value_datetime} value_date=${value_date} value_time=${value_time} date_time_tz=${date_time_tz}`);
}
/* *** END *** Input type specific */
/* THIS NEEDS TO BE CLEANED UP */
let multipart_style;
let label_begin;
let checkbox_none;
let checked;
let checkbox_none_text;
let checkbox_li;
let radio_option_class_li;
let radio_none;
let radio_none_text;
let radio_li;
let value_new_line;
let select_option_none;
let select_option_li_lu_name;
let select_option_li;
let select_option_none_text;
/* ^^^ THIS NEEDS TO BE CLEANED UP ^^^ */
const dispatch = createEventDispatcher();
// type Input = {
// name: string;
// value: number;
// };
// let input: Input;
/*
* container_element: span, div, section
* container_class_li: []
* content_layout: inline, break, bs_floating
* content_order: label_value_description, value_label_description, label_description_value
* label_class_li: []
* class_li: []
* start_desc: string
* end_desc: string
*
*/
onMount(() => {
console.log(`** Element Mounted: ** Element Input v2: ${obj_type} ${obj_prop_name}; type=${data_type}; value=${value}`);
if (input_mode == 'editor_basic_200') {
rich_editor();
}
});
// $: if (value) {
// console.log(`input name=${name} value=${value}`);
// console.log(typeof value);
// } else if (typeof value === 'undefined') {
// console.log(`input name=${name} value=undefined; resetting to ''`);
// value = '';
// }
$: if (disabled) { disabled=true; } // else { disabled=false; }
$: if (readonly) { readonly=true; } // else { readonly=false; }
$: if (required) { required=true; } // else { required=true; }
$: if (data_type) {
console.log(`Input value data_type=${data_type}`);
} else if (data_type == 'json') {
console.log(`Need to convert JSON object to string.`);
if (typeof value === 'object') {
value = JSON.stringify(value);
console.log(`Value as data type (${data_type}): ${value}`);
} else {
console.log('Value is not an object type')
console.log(typeof value);
}
}
// // input_mode options: null or '' assume 'text', 'none', 'text', 'tel', 'url', 'email', 'numeric', 'decimal', and 'search'
// $: if (input_mode === null || input_mode == '') {
// input_mode = 'text';
// } else if (input_mode == 'json') {
// } else if (input_mode == 'editor_basic_200') {
// }
// console.log(`input_mode=${input_mode}`);
$: if (container_display == '' || container_display == 'block') {
console.log(`input name=${name} container_display=${container_display}`);
// NOTE: Using a div will be displayed as block by default
} else if (container_display == 'inline') {
console.log(`input name=${name} container_display=${container_display}`);
container_class_li.push('container_inline');
container_style = 'display: inline;'
} else if (container_display == 'inline-block') {
console.log(`input name=${name} container_display=${container_display}`);
container_class_li.push('container_inline_block');
container_style = 'display: inline-block;'
} else if (typeof container_display === 'undefined') {
console.log(`input name=${name} container_display=${container_display}`);
}
$: if (content_layout == '' || content_layout == 'label_begin') {
console.log(`input name=${name} content_layout=${content_layout}`);
// label_begin = true;
} else if (content_layout == 'label_end') {
console.log(`input name=${name} content_layout=${content_layout}`);
// label_begin = false;
} else if (content_layout == 'floating_input') {
console.log(`input name=${name} content_layout=${content_layout}`);
// label_begin = false;
if (type != 'date_time') {
container_class_li.push('form-floating'); // set the container class list
} else {
multipart_class_li.push('form-floating'); // set the container with multi input parts class list
}
if (type === 'select') {
class_li.push('form-select'); // set the select class list
} else {
console.log('Make form-control???');
class_li.push('form-control'); // set the input, select, textarea class list
}
if (type === 'textarea') {
let estimate_row_rem = rows + 5.5;
style = `height: calc(2px + ${estimate_row_rem}rem);`;
}
} else if (typeof content_layout === 'undefined') {
console.log(`input name=${name} content_layout=${content_layout}`);
}
// function handle_oninput_dispatch() {
// console.log(input);
// dispatch('oninput', {
// name: input.name,
// value: input.value,
// });
// }
function handle_oninput_dispatch(event) {
console.log(event.target);
console.log(value);
dispatch('oninput', {
name: event.target.name,
value: event.target.value,
});
}
function rich_editor() {
console.log('*** rich_editor() ***');
// let test_element = $('.editor_basic_200');
// console.log(test_element);
// let textarea_element = document.querySelector('.editor_basic_200');
// let toolbar_element = document.querySelector('.quilljs_toolbar');
// console.log(toolbar_element);
let editor_element = document.querySelector('.quilljs_editor');
console.log(editor_element);
// var editor = new Quill(editor_element, {
// modules: {
// 'multi-cursor': true,
// 'toolbar': { container: '#quilljs_toolbar' },
// // 'link-tooltip': true,
// },
// placeholder: 'Text goes here',
// theme: 'snow'
// });
var editor = new Quill(editor_element, {
modules: {
'multi-cursor': true,
toolbar: [
[{
header: [1, 2, false]
}],
['bold', 'italic', 'underline'],
['image', 'code-block']
]
// 'link-tooltip': true,
},
placeholder: 'Text goes here',
theme: 'snow'
});
/*
textarea_element.summernote(
{
tabsize: 4,
height: 200,
toolbar: [
['cleaner',['cleaner']], // The Button
['edit', ['undo', 'redo']],
['font', ['bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript', 'clear']],
['color', ['forecolor']],
['para', ['ul', 'ol', 'paragraph']],
['insert', ['link']],
['view', ['codeview', 'help']]
],
cleaner:{
action: 'both', // both|button|paste 'button' only cleans via toolbar button, 'paste' only clean when pasting content, both does both options.
newline: '<br>', // Summernote's default is to use '<p><br></p>'
notStyle: '', // Position of Notification
icon: '<i class="fas fa-paste"></i>',
keepHtml: true, // Remove all Html formats
keepOnlyTags: ['<p>', '<br>', '<ul>', '<li>', '<b>', '<strong>','<i>', '<a>'], // If keepHtml is true, remove all tags except these
keepClasses: false, // Remove Classes
badTags: ['style', 'script', 'applet', 'embed', 'noframes', 'noscript', 'html'], // Remove full tags with contents
badAttributes: ['style', 'start'], // Remove attributes from remaining tags
limitChars: false, // 0/false|# 0/false disables option
limitDisplay: 'none', // none|text|html|both
limitStop: false // true/false
}
});
*/
}
</script>
<div class="element element_input {container_class_li.join(' ')}" style={container_style}>
{#if type === 'email' || type === 'date' || type === 'number' || type === 'tel' || type === 'text' || type === 'time' || type === 'url' }
{#if (content_layout == 'label_start' && label)}
<label for={id} class={label_class_li.join(' ')} style={label_style}>{label}</label>
{/if}
<input {id} {name} class={class_li.join(' ')} {style} use:set_input_type {placeholder} {size} {pattern} {readonly} {disabled} {required} inputmode={input_mode} data-id_random={id_random} data-obj_type={obj_type} data-obj_prop_name={obj_prop_name} use:util.set_focus={focus} on:input={handle_oninput_dispatch} bind:value={value} />
{#if (content_layout != 'label_start' && label)}
<label for={id} class={label_class_li.join(' ')} style={label_style}>{label}</label>
{/if}
<span>{description}</span>
{:else if type === 'date_time' }
{#if (content_layout == 'label_start' && label)}
<span class={label_class_li.join(' ')} style={label_style}>{label}</span>
<!-- <label for={id} class={label_class_li.join(' ')} style={label_style}>{label}</label> -->
{/if}
<div class="element_input multipart {multipart_class_li.join(' ')}" style={multipart_style}>
{#if label_begin}
<label for={`${id}_date`} class={label_class_li.join(' ')} style={label_style}>{label_date}</label>
{/if}
<input id={id+'_date'} name={name+'_date'} {style} class={class_li.join(' ')} type="date" value={value_date} {placeholder} {readonly} {disabled} {required} data-id_random={id_random} data-obj_type={obj_type} data-obj_prop_name={obj_prop_name} on:input={handle_oninput_dispatch} />
{#if !label_begin}
<label for={`${id}_date`} class={label_class_li.join(' ')} style={label_style}>{label_date}</label>
{/if}
</div>
<div class="element_input multipart {multipart_class_li.join(' ')}" style={multipart_style}>
{#if label_begin}
<label for={`${id}_time`} class={label_class_li.join(' ')} style={label_style}>{label_time}</label>
{/if}
<input id={id+'_time'} name={name+'_time'} {style} class={class_li.join(' ')} type="time" value={value_time} {placeholder} {readonly} {disabled} {required} data-id_random={id_random} data-obj_type={obj_type} data-obj_prop_name={obj_prop_name} on:input={handle_oninput_dispatch} />
{#if !label_begin}
<label for={`${id}_time`} class={label_class_li.join(' ')} style={label_style}>{label_time}</label>
{/if}
</div>
{#if (content_layout != 'label_start' && label)}
<span class={label_class_li.join(' ')} style={label_style}>{label}</span>
<!-- <label for={id} class={label_class_li.join(' ')} style={label_style}>{label}</label> -->
{/if}
<span>{description}</span>
{:else if type === 'checkbox' }
{#if checkbox_none}
{#if !value}
{checked='checked'}
{/if}
<label>{checkbox_none_text}
<input {name} type="checkbox" value="" {readonly} {disabled} {required} {checked} on:input={handle_oninput_dispatch} />
</label>
{/if}
{#if checkbox_li.length}
{#if (content_layout == 'label_start' && label)}
<span class="input_container_label label_begin">{label}</span>
{/if}
{#each Object.entries(checkbox_li) as [li_key, li_value]}
{#if li_key.toString() === value.toString() }
<label>{li_value}
<input {name} type="checkbox" value="{li_key}" checked on:input={handle_oninput_dispatch}>
</label>
{:else}
<label>{li_value}
<input {name} type="checkbox" value="{li_key}" on:input={handle_oninput_dispatch}>
</label>
{/if}
{/each}
{#if (content_layout != 'label_start' && label)}
<span class="input_container_label label_end">{label}</span>
{/if}
{:else}
{#if label_begin}
<label for={id} class={label_class_li.join(' ')} style={label_style}>{label}</label>
{/if}
<input {id} {name} class={class_li.join(' ')} {style} type="checkbox" {value} {placeholder} {readonly} {disabled} {required} data-id_random={id_random} data-obj_type={obj_type} data-obj_prop_name={obj_prop_name} {checked} on:input={handle_oninput_dispatch} />
{/if}
<span>{description}</span>
{:else if type === 'radio' }
{#if radio_none}
{#if !value}
{checked='checked'}
{/if}
<label class={radio_option_class_li.join(' ')}>{@html radio_none_text}
<input {name} type="radio" value="" {readonly} {disabled} {required} {checked} on:input={handle_oninput_dispatch} />
</label>
{/if}
{#if radio_li}
{#if (content_layout == 'label_start' && label)}
<span class="input_container_label label_begin">{label}:</span>
{/if}
<span class="input_container_radio_options">
{#each Object.entries(radio_li) as [li_key, li_value]}
{#if value === null} <!-- If null then no option should be selected. -->
<label>{@html li_value}
<input {name} type="radio" bind:group={value} value="{li_key}" on:input={handle_oninput_dispatch}>
</label>
{:else if ( li_key.toString() === value.toString() || (li_key == 'true' && value == true) || (li_key == 'false' && value == false) ) }
<label>{@html li_value}
<input {name} type="radio" bind:group={value} value="{li_key}" checked on:input={handle_oninput_dispatch}> Z
</label>
{:else}
<label>{@html li_value}
<input {name} type="radio" bind:group={value} value="{li_key}" on:input={handle_oninput_dispatch}>
</label>
{/if}
<!-- <label>{@html li_value}
<input {name} type="radio" bind:group={value} value="{li_key}" on:input={handle_oninput_dispatch}>
</label> -->
{/each}
</span>
{#if !label_begin}
<span class="input_container_label label_end">{label}:</span>
{/if}
{:else}
{#if label_begin}
<label for={id} class={label_class_li.join(' ')} style={label_style}>{@html label}</label>
{/if}
<input {id} {name} class={class_li.join(' ')} {style} type="radio" {value} {placeholder} {readonly} {disabled} {required} data-id_random={id_random} data-obj_type={obj_type} data-obj_prop_name={obj_prop_name} {checked} on:input={handle_oninput_dispatch} />
{#if !label_begin}
<label for={id} class={label_class_li.join(' ')} style={label_style}>{@html label}</label>
{/if}
{/if}
<span>{description}</span>
{:else if type === 'textarea'}
{#if label_begin}
<label for={id} class={label_class_li.join(' ')} style={label_style}>{label}</label>
{/if}
{#if value_new_line}<br>{/if}
<textarea {id} {name} class={class_li.join(' ')} {style} bind:value={value} {placeholder} {readonly} {disabled} {required} {rows} {cols} data-id_random={id_random} data-obj_type={obj_type} data-obj_prop_name={obj_prop_name} on:input={handle_oninput_dispatch}></textarea>
<!-- rows="" cols="" maxlength="" -->
{#if !label_begin}
<label for={id} class={label_class_li.join(' ')} style={label_style}>{label}</label>
{/if}
<span>{description}</span>
{:else if type === 'hidden'}
<input {id} {name} class={class_li.join(' ')} type="hidden" bind:value={value} {placeholder} {readonly} {disabled} {required} data-id_random={id_random} data-obj_type={obj_type} data-obj_prop_name={obj_prop_name} />
{:else if type === 'select'}
{#if label_begin}
<label for={id} class={label_class_li.join(' ')} style={label_style}>
{label}
<!-- {#if value} <span class="label_select_value">{value}</span>{/if} -->
</label>
{/if}
<select {id} {name} class={class_li.join(' ')} {style} {readonly} {disabled} {required} data-id_random={id_random} data-obj_type={obj_type} data-obj_prop_name={obj_prop_name} on:input={handle_oninput_dispatch}>
{#if select_option_none}
<option value="">{select_option_none_text}</option>
{/if}
{#if select_option_li_lu_name}
<!-- <Select_element_lu lu_list_name={select_option_li_lu_name} params={select_option_li_lu_params} value_field_name={select_option_lu_value_field_name} text_field_name={select_option_lu_text_field_name} slct_value={value} /> -->
{:else}
{#each Object.entries(select_option_li) as [li_key, li_value]}
{#if value === null} <!-- If null then no option should be selected. -->
<option value="{li_key}">
{li_value}
</option>
{:else if li_key.toString() === value.toString() }
<option value="{li_key}" selected>
{li_value}
</option>
{:else}
<option value="{li_key}">
{li_value}
</option>
{/if}
{/each}
{/if}
</select>
{#if !label_begin}
<label for={id} class={label_class_li.join(' ')} style={label_style}>
{label}
{#if value} <span class="label_select_value">{value}</span>{/if}
</label>
{/if}
<span>{description}</span>
{/if}
<slot name="more_html">
</slot>
</div>
<style>
.container_inline {
display: inline;
}
</style>

View File

@@ -0,0 +1,580 @@
<script lang="ts">
import { onMount } from 'svelte';
import { clipboard } from '@skeletonlabs/skeleton';
// import { liveQuery } from "dexie";
import type { key_val } from '$lib/ae_stores';
import { ae_util } from '$lib/ae_utils';
import { api } from '$lib/api';
// import Element_ae_crud from '$lib/element_ae_crud.svelte';
// import Element_data_store from '$lib/element_data_store.svelte';
// import { core_func } from '$lib/ae_core_functions';
import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
import { db_events } from "$lib/db_events";
import { events_loc, events_sess, events_slct, events_trigger } from '$lib/ae_events_stores';
import { events_func } from '$lib/ae_events_functions';
export let container_class_li: string|Array<string> = [];
export let lq__event_file_obj_li: any;
export let link_to_type: string;
export let link_to_id: string;
export let allow_basic: boolean = false;
export let allow_moderator: boolean = false;
export let display_mode: string = 'default'; // 'default', 'compact', 'minimal', 'launcher'
// export let show_convert_btn: null|boolean = null;
// let ae_placeholder_li: key_val = {};
let ae_promises: key_val = {};
let ae_tmp: key_val = {};
ae_tmp.show__file_li = true;
ae_tmp.show__direct_download = false;
// let ae_triggers: key_val = {};
// let dq__where_val: string = `${link_to_type}_id_random`;
// let dq__where_eq_val: string = link_to_id;
// let lq__event_file_obj_li = liveQuery(
// async () => await db_events.files
// .where(dq__where_val)
// .equals(dq__where_eq_val)
// .toArray()
// );
onMount(() => {
// console.log('Element - Manage Event File List');
console.log(`link_to_type: ${link_to_type}; link_to_id: ${link_to_id}`);
console.log(`allow_basic: ${allow_basic}; allow_moderator: ${allow_moderator}`);
// $slct_trigger = 'load__event_file_obj_li';
});
</script>
<div
class="float-right flex flex-row items-center"
>
<button
type="button"
on:click={() => {
console.log('*** Refresh button clicked ***');
db_events.files.clear();
let params = {
qry__enabled: 'all',
qry__hidden: 'all',
}
events_func.handle_load_ae_obj_li__event_file({
api_cfg: $ae_api,
for_obj_type: link_to_type,
for_obj_id: link_to_id,
params: params,
try_cache: true
});
// ae_tmp.show__file_li = false;
// console.log(`$lq__event_file_obj_li:`, $lq__event_file_obj_li);
// $slct_trigger = 'load__event_file_obj_li';
// ae_tmp.show__file_li = true;
}}
class="btn btn-sm p-1 m-1 variant-soft-tertiary hover:variant-ghost-warning transition hover:transition-all *:hover:inline"
class:hidden={!$ae_loc.authenticated_access}
title="Refresh the list of files"
>
<span class="fas fa-sync-alt m-1"></span>
<div class="hidden">
Files
</div>
</button>
<button
type="button"
on:click={() => {
console.log('*** Show Alt Download button clicked ***');
ae_tmp.show__direct_download = !ae_tmp.show__direct_download;
}}
class="btn btn-sm p-1 m-1 variant-soft-tertiary hover:variant-ghost-warning transition hover:transition-all *:hover:inline"
class:hidden={!$ae_loc.trusted_access}
title="Toggle direct download link and copy link button"
>
<span class="fas fa-download m-1"></span>
<div class="hidden">
{ae_tmp.show__direct_download ? 'Alt On' : 'Alt Download Off'}
</div>
</button>
</div>
<section class="svelte_component event_file_uploaded_manage {container_class_li}"
class:text-sm={display_mode != 'default'}
>
<h3
class="h6"
class:hidden={!$lq__event_file_obj_li?.length || display_mode != 'default'}
>
Manage Files:
<span class="font-bold bg-success-100 px-4 border rounded-lg border-success-200"
title="Files for {link_to_type ?? '-- not set --'}: {link_to_id ?? '-- not set --'} (files: {$lq__event_file_obj_li?.length ?? 'None'})"
>
<span class="fas fa-folder-open mx-1"></span>
{@html $lq__event_file_obj_li ? `${$lq__event_file_obj_li.length}&times;` : '-- none --'}
</span>
</h3>
{#if $lq__event_file_obj_li && $lq__event_file_obj_li.length}
<div class="overflow-auto w-full">
<table class="table-auto w-full">
{#if display_mode === 'default'}
<thead>
<tr>
<th class="text-center">Download File</th>
{#if display_mode === 'default'}
<th
class="text-center"
class:hidden={!allow_basic && !$ae_loc.trusted_access}
>Options</th>
{/if}
{#if display_mode === 'default'}
<th
class="text-center"
class:hidden={!allow_basic && !$ae_loc.trusted_access}
>Status</th>
{/if}
<th class="text-center">Meta</th>
</tr>
</thead>
{/if}
<tbody>
{#each $lq__event_file_obj_li as event_file_obj}
<tr
class="ae_obj obj_event_file border-t border-b border-gray-200 hover:bg-gray-50 hover:border-gray-300"
class:dim={event_file_obj?.hide}
>
<td class="event_file__file align-middle">
{#if $events_sess.pres_mgmt?.show_field_edit__filename != event_file_obj.event_file_id_random}
<button
disabled={!allow_basic && !allow_moderator && !$ae_loc.trusted_access}
on:click={() => {
// ae_promises[event_file_obj.event_file_id_random]
ae_promises[event_file_obj.event_file_id_random] = api.download_hosted_file({
api_cfg: $ae_api,
hosted_file_id: event_file_obj.hosted_file_id_random,
return_file: true,
filename: event_file_obj.filename,
auto_download: true,
log_lvl: 0
});
// window.postMessage({ type: 'download_event_file', event_file_id: event_file_obj.event_file_id_random, filename: event_file_obj.filename, auto_download: true }, '*');
}}
class="btn btn-sm lg:btn-md variant-soft-primary hover:variant-filled-primary min-w-72 lg:min-w-96"
title={`Download this file:\n${event_file_obj.filename}\n[API] SHA256: ${event_file_obj.hash_sha256.slice(0, 10)}... Hosted ID: ${event_file_obj.hosted_file_id_random} Event File ID: ${event_file_obj.event_file_id_random}`}
>
{#await ae_promises[event_file_obj.event_file_id_random]}
<span class="fas fa-spinner fa-spin mx-1"></span>
<span class="">
Downloading
{#if $ae_sess.api_download_kv[event_file_obj.hosted_file_id_random]}
{$ae_sess.api_download_kv[event_file_obj.hosted_file_id_random].percent_completed}%
{/if}
:
</span>
{:then}
<!-- <span class="fas fa-download mx-1"></span> -->
<span class="fas fa-{ae_util.file_extension_icon(event_file_obj.extension)}"></span>
<!-- <span class="text-sm">
Download:
</span> -->
{/await}
<span class="grow">
{ae_util.shorten_filename({filename: event_file_obj.filename, max_length: 30})}
</span>
<span
class="badge variant-glass-success hover:variant-filled-success text-sm"
class:hidden={!event_file_obj.file_purpose}
>
{event_file_obj.file_purpose}
</span>
</button>
<a
href="{$ae_api.base_url}/event/file/{event_file_obj.event_file_id_random}/download?filename={event_file_obj.filename}&x_no_account_id_token=direct-download"
class="btn btn-sm variant-soft-secondary m-0.5 *:hover:inline"
class:hidden={!ae_tmp.show__direct_download}
title={`Download this file:\n${event_file_obj.filename}\n[API] SHA256: ${event_file_obj.hash_sha256.slice(0, 10)}... Hosted ID: ${event_file_obj.hosted_file_id_random} Event File ID: ${event_file_obj.event_file_id_random}`}
>
<span class="fas fa-download mx-1"></span>
<div class="hidden">
Download
</div>
</a>
<button
type="button"
use:clipboard={encodeURI(`${$ae_api.base_url}/event/file/${event_file_obj.event_file_id_random}/download?filename=${event_file_obj.filename}&x_no_account_id_token=direct-download`)}
class="btn btn-sm variant-soft-secondary m-0.5 *:hover:inline"
class:hidden={!ae_tmp.show__direct_download}
title="Copy the direct download file link to the clipboard."
>
<span class="fas fa-copy mx-1"></span>
<div class="hidden">
Copy Link
</div>
</button>
{:else}
<!-- Show change filename input field here -->
<span
class="flex flex-col gap-1 text-sm"
>
<input
type="text"
size="12"
placeholder="Filename"
bind:value="{$events_sess.pres_mgmt.tmp_val__filename_no_ext}"
data-original_value="{event_file_obj.filename}"
class="input min-w-72 lg:min-w-96 text-sm bg-warning-100"
title="Rename this file. No extension."
>
{#if $events_sess.pres_mgmt.tmp_val__filename_no_ext.trim() != event_file_obj.filename_no_ext}
<button
on:click={async () => {
let new_filename = $events_sess.pres_mgmt.tmp_val__filename_no_ext.trim()
// Remove possible double extension
new_filename = new_filename.replace('.'+event_file_obj.extension, '');
// Add the extension back
new_filename = new_filename + '.' + event_file_obj.extension;
// Remove any double dots
new_filename = new_filename.replace(/\.\./g, '.');
let event_file_data = {
filename: new_filename,
};
ae_promises.update__event_file_obj = events_func.handle_update_ae_obj__event_file({
api_cfg: $ae_api,
event_file_id: event_file_obj.event_file_id_random,
data_kv: event_file_data,
log_lvl: 0
})
.then (function (update_results) {
console.log(`Update results:`, update_results);
$events_sess.pres_mgmt.show_field_edit__filename = false;
});
}}
class="btn btn-sm variant-glass-tertiary hover:variant-soft-success"
title="Save changes"
>
{#await ae_promises.update__event_file_obj}
<span class="fas fa-spinner fa-spin mx-1"></span>
<span class="">Saving {event_file_obj.extension}</span>
{:then}
<span class="fas fa-save mx-1"></span>
Save {event_file_obj.extension} filename?
{/await}
</button>
{/if}
</span>
{/if}
</td>
{#if display_mode === 'default'}
<td
class="event_file__options"
class:hidden={!allow_basic && !$ae_loc.trusted_access}
>
<div class="flex flex-col gap-1 text-sm">
<button
disabled={!allow_basic && !$ae_loc.trusted_access}
on:click={() => {
if ($events_sess.pres_mgmt.show_field_edit__filename == event_file_obj.event_file_id_random) {
$events_sess.pres_mgmt.tmp_val__filename_no_ext = '';
$events_sess.pres_mgmt.show_field_edit__filename = false;
} else {
$events_sess.pres_mgmt.tmp_val__filename_no_ext = event_file_obj.filename_no_ext;
$events_sess.pres_mgmt.show_field_edit__filename = event_file_obj.event_file_id_random;
}
}}
class="btn btn-sm variant-glass-tertiary hover:variant-soft-success"
class:variant-glass-warning={$events_sess.pres_mgmt.show_field_edit__filename == event_file_obj.event_file_id_random}
title={`Rename this file? "${event_file_obj.filename}"`}
>
<span class="fas fa-edit mx-1"></span>
{#if $events_sess.pres_mgmt?.show_field_edit__filename == event_file_obj.event_file_id_random}
Cancel?
{:else}
Rename
{/if}
</button>
<button
disabled={!allow_basic && !$ae_loc.trusted_access}
on:click={async () => {
let event_file_data = {
hide: !event_file_obj.hide,
};
ae_promises.update__event_file_obj = events_func.handle_update_ae_obj__event_file({
api_cfg: $ae_api,
event_file_id: event_file_obj.event_file_id_random,
data_kv: event_file_data,
log_lvl: 1
})
.then (function (update_results) {
console.log(`Update results:`, update_results);
let params = {
qry__enabled: 'all',
qry__hidden: 'all',
}
events_func.handle_load_ae_obj_li__event_file({
api_cfg: $ae_api,
for_obj_type: link_to_type,
for_obj_id: link_to_id,
params: params,
try_cache: true
});
});
}}
class="btn btn-sm variant-glass-tertiary hover:variant-soft-success"
title="Hide this file from the presentation launcher"
>
<!-- Users see this as the "Archive" option button -->
<!-- {@html (event_file_obj?.hide ? '<span class="fas fa-archive m-1"></span> Unarchive' : '<span class="fas fa-archive m-1"></span> Archive')} -->
{#await ae_promises.update__event_file_obj}
<span class="fas fa-spinner fa-spin mx-1"></span>
<span class="">Saving {event_file_obj.extension}</span>
{:then}
{#if event_file_obj.hide}
<span class="fas fa-eye m-1"></span> Unhide File
{:else}
<span class="fas fa-eye-slash m-1"></span> Hide
{/if}
<!-- {@html (event_file_obj?.hide ? '<span class="fas fa-eye m-1"></span> Unhide?' : '<span class="fas fa-eye-slash m-1"></span> Hide?')} -->
<!-- <span class="fas fa-save mx-1"></span>
Save {event_file_obj.extension} filename? -->
{/await}
</button>
<button
disabled={!allow_basic && !$ae_loc.trusted_access}
on:click={async () => {
if (!confirm(`Are you sure you want to delete this file?\n${event_file_obj.filename} [${event_file_obj.event_file_id_random}]`)) {return false;}
// ae_promises[event_file_obj.event_file_id_random] = handle_delete__event_file({event_file_id: event_file_obj.event_file_id_random});
ae_promises.delete__event_file_obj = await events_func.handle_delete_ae_obj_id__event_file({
api_cfg: $ae_api,
event_file_id: event_file_obj.event_file_id_random,
log_lvl: 1
})
}}
class="btn btn-sm variant-glass-tertiary hover:variant-soft-success"
title="Delete this file"
>
<span class="fas fa-trash-alt mx-1"></span>
<!-- <span class="fas fa-minus mx-1"></span> -->
Delete
</button>
</div>
</td>
{/if}
{#if display_mode === 'default'}
<td
class="event_file__status"
class:hidden={!allow_basic && !$ae_loc.trusted_access}
>
<div class="flex flex-col gap-1 items-center text-sm">
<div class="">
{#if event_file_obj.open_in_os == 'win'}
MS Windows <span class="fab fa-windows"></span>
{:else if event_file_obj.open_in_os == 'mac'}
Apple macOS <span class="fab fa-apple"></span>
{/if}
</div>
<!-- Select from options for the purpose of this file -->
<div>
<label
for="file_purpose"
class="text-sm mx-1 hidden"
>
Purpose:
</label>
<select
id="file_purpose"
name="file_purpose"
disabled={!allow_basic && !allow_moderator && !$ae_loc.trusted_access}
value={event_file_obj.file_purpose}
on:change={e => {
// ae_tmp[event_file_obj.event_file_id_random].file_purpose = e.target.value;
console.log(`Selected file_purpose: ${e.target.value}`);
let event_file_data = {
event_file_id_random: event_file_obj.event_file_id_random,
file_purpose: e.target.value,
};
events_func.handle_update_ae_obj__event_file({
api_cfg: $ae_api,
event_file_id: event_file_obj.event_file_id_random,
data_kv: event_file_data,
log_lvl: 1
})
.then (function (update_results) {
console.log(`Update results:`, update_results);
$slct_trigger = 'load__event_file_obj_li';
});
// ae_triggers.update_event_file_purpose = true;
}}
class="select min-w-fit max-w-fit text-sm mx-1 border border-gray-300 rounded-md p-1 hover:border-gray-400"
>
<option value={null} selected={!event_file_obj.file_purpose} class="text-xs">-- purpose not set --</option>
<option value="outline" selected={event_file_obj.file_purpose === 'outline'}>1. Outline</option>
<option value="draft" selected={event_file_obj.file_purpose === 'draft'}>2. Draft</option>
<option value="final" selected={event_file_obj.file_purpose === 'final'}>3. Final</option>
<!-- <option value="supporting">X. Supporting File (audio, video, data, etc)</option> -->
<!-- <option value="handout">X. Handout</option> -->
<option value="other">X. Other</option>
<!-- <option value="poster">Final - Poster</option> -->
<!-- <option value="presentation">Final - Presentation</option> -->
<!-- Shows in session room -->
</select>
</div>
</div>
</td>
{/if}
<td class="event_file_info file_meta text-gray-500">
<div
class="flex flex-col gap-0.5 text-xs"
>
<!-- {event_file_obj.hosted_file_content_type} -->
<span class="w-full flex flex-col lg:flex-row justify-between">
<span
class:hidden={display_mode != 'default'}
>
Type:
<strong>{event_file_obj.extension} <span class="fas fa-{ae_util.file_extension_icon(event_file_obj.extension)}"></span>
</strong>
<!-- {#if event_file_obj.open_in_os == 'win'}
<strong>
MS Windows <span class="fab fa-windows"></span>
</strong>
{:else if event_file_obj.open_in_os == 'mac'}
<strong>
Apple macOS <span class="fab fa-apple"></span>
</strong>
{/if} -->
</span>
<span>
<span
class:hidden={display_mode != 'default'}
>
Size:
</span>
<strong>{ae_util.format_bytes(event_file_obj.file_size)}</strong>
</span>
</span>
<span class="w-full flex flex-col lg:flex-row justify-between">
<span title="SHA 256: {event_file_obj.hash_sha256}">
<span
class:hidden={display_mode != 'default'}
>
Hash:
</span>
<strong
class:font-normal={display_mode != 'default'}
>{event_file_obj.hash_sha256.slice(0, 10)}&mldr;</strong>
</span>
<span
class:hidden={!$ae_loc.administrator_access || display_mode != 'default'}>
<span
class:hidden={display_mode != 'default'}
>
ID:
</span>
<strong>{event_file_obj.hosted_file_id_random}</strong>
</span>
</span>
<span>
{#if display_mode == 'default'}
<!-- <span class="fas fa-cloud-upload-alt mx-1"></span> -->
<!-- Uploaded: -->
<!-- <span class="fas fa-calendar-day mx-1"></span> -->
<span class="fas fa-clock mx-1"></span>
<strong>
{ae_util.iso_datetime_formatter(event_file_obj.created_on, 'dddd')}
</strong>
{ae_util.iso_datetime_formatter(event_file_obj.created_on, 'date_iso')}
at
<strong>{ae_util.iso_datetime_formatter(event_file_obj.created_on, 'time_us_short_no_leading')}</strong>
<!-- {event_file_obj.updated_on} -->
{:else}
<!-- <span class="fas fa-calendar-day mx-1"></span> -->
<strong>
{ae_util.iso_datetime_formatter(event_file_obj.created_on, 'date_short')}
<!-- at -->
<strong>{ae_util.iso_datetime_formatter(event_file_obj.created_on, 'time_us_short_no_leading')}</strong>
</strong>
{/if}
</span>
</div>
</td>
</tr>
{/each}
</tbody>
</table>
</div>
{:else}
<p
class="w-96 text-center text-gray-500"
class:hidden={display_mode != 'default'}
>
No files uploaded to display
</p>
{/if}
</section>
<style>
</style>

View File

@@ -0,0 +1,62 @@
<script lang="ts">
import { onMount } from 'svelte';
// import { clipboard } from '@skeletonlabs/skeleton';
import { liveQuery } from "dexie";
import type { key_val } from '$lib/ae_stores';
// import { ae_util } from '$lib/ae_utils';
// import { api } from '$lib/api';
// import Element_ae_crud from '$lib/element_ae_crud.svelte';
// import Element_data_store from '$lib/element_data_store.svelte';
import Element_manage_event_file_li from '$lib/element_manage_event_file_li.svelte';
// import { core_func } from '$lib/ae_core_functions';
import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
import { db_events } from "$lib/db_events";
// import { events_loc, events_sess, events_slct, events_trigger } from '$lib/ae_events_stores';
// import { events_func } from '$lib/ae_events_functions';
export let container_class_li: string|Array<string> = [];
export let link_to_type: string;
export let link_to_id: string;
export let allow_basic: boolean = false;
export let allow_moderator: boolean = false;
export let display_mode: string = 'default'; // 'default', 'compact', 'minimal', 'launcher'
// export let show_convert_btn: null|boolean = null;
// let ae_placeholder_li: key_val = {};
// let ae_promises: key_val = {};
let ae_tmp: key_val = {};
ae_tmp.show__file_li = true;
ae_tmp.show__direct_download = false;
// let ae_triggers: key_val = {};
let dq__where_val: string = `${link_to_type}_id_random`;
let dq__where_eq_val: string = link_to_id;
let lq__event_file_obj_li = liveQuery(
async () => await db_events.files
.where(dq__where_val)
.equals(dq__where_eq_val)
.toArray()
);
onMount(() => {
// console.log('Element - Manage Event File List');
// console.log(`link_to_type: ${link_to_type}; link_to_id: ${link_to_id}`);
$slct_trigger = 'load__event_file_obj_li';
});
</script>
<Element_manage_event_file_li
link_to_type={link_to_type}
link_to_id={link_to_id}
lq__event_file_obj_li={lq__event_file_obj_li}
allow_basic={allow_basic}
allow_moderator={allow_moderator}
container_class_li={container_class_li}
display_mode={display_mode}
/>

View File

@@ -0,0 +1,73 @@
<script lang="ts">
import { onMount } from 'svelte';
// import { clipboard } from '@skeletonlabs/skeleton';
import { liveQuery } from "dexie";
import type { key_val } from '$lib/ae_stores';
// import { ae_util } from '$lib/ae_utils';
// import { api } from '$lib/api';
// import Element_ae_crud from '$lib/element_ae_crud.svelte';
// import Element_data_store from '$lib/element_data_store.svelte';
import Element_manage_event_file_li from '$lib/element_manage_event_file_li.svelte';
// import { core_func } from '$lib/ae_core_functions';
import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
import { db_events } from "$lib/db_events";
// import { events_loc, events_sess, events_slct, events_trigger } from '$lib/ae_events_stores';
// import { events_func } from '$lib/ae_events_functions';
export let container_class_li: string|Array<string> = [];
export let link_to_type: string;
export let link_to_id: string;
export let allow_basic: boolean = false;
export let allow_moderator: boolean = false;
export let display_mode: string = 'default'; // 'default', 'compact', 'minimal', 'launcher'
// export let show_convert_btn: null|boolean = null;
// let ae_placeholder_li: key_val = {};
// let ae_promises: key_val = {};
let ae_tmp: key_val = {};
ae_tmp.show__file_li = true;
ae_tmp.show__direct_download = false;
// let ae_triggers: key_val = {};
let dq__where_val: string = `for_type`;
let dq__where_eq_val: string = link_to_type;
let dq__where_for_id_eq_val: string = link_to_id;
let lq__event_file_obj_li = liveQuery(
async () => await db_events.files
.where(dq__where_val)
.equals(dq__where_eq_val)
.and(file => file.for_id_random == dq__where_for_id_eq_val)
.toArray()
);
onMount(() => {
// console.log('Element - Manage Event File List');
// console.log(`link_to_type: ${link_to_type}; link_to_id: ${link_to_id}`);
$slct_trigger = 'load__event_file_obj_li';
});
</script>
{#await lq__event_file_obj_li}
<p>Loading...</p>
{:then lq__event_file_obj_li}
<Element_manage_event_file_li
link_to_type={link_to_type}
link_to_id={link_to_id}
lq__event_file_obj_li={lq__event_file_obj_li}
allow_basic={allow_basic}
allow_moderator={allow_moderator}
container_class_li={container_class_li}
display_mode={display_mode}
/>
{:catch error}
<p style="color: red;">{error.message}</p>
{/await}

View File

@@ -0,0 +1,146 @@
<script lang="ts">
import { onMount } from 'svelte';
// This (ae) is only used for utilities
// import { ae } from 'aether_npm_lib';
import { ae_util } from '$lib/ae_utils';
// These (slct_*) are only used internally for this component. Not needed???
// import { slct_obj_id, slct_obj_li_type, slct_obj_type } from '../admin/stores_admin.js';
// Should these slct_* be exported???
let slct_obj_id = null;
let slct_obj_li_type = null;
let slct_obj_type = null;
export let row_header: boolean = false;
export let primary_obj_li_type: string = slct_obj_li_type; // account, person, user, event, event_session, membership_person
export let obj = null;
console.log(obj);
console.log(typeof obj);
onMount(() => {
console.log('** Element Mounted: ** Element Object Table Row');
if (obj) {
console.log('Table Row Object:', obj);
// console.log(typeof obj);
} else {
return false;
}
});
/* BEGIN: Handle requests (archive, create, hide, remove, select, update, POST, PATCH, GET, DELETE) */
/* END: Handle requests (archive, create, hide, remove, select, update, POST, PATCH, GET, DELETE) */
/* BEGIN: Handle other local actions (show/hide form, process data) */
/* END: Handle other local actions (show/hide form, process data) */
/* BEGIN: Handle children events (archived, canceled, closed, created, deleted, hidden, updated) */
/* END: Handle children events (archived, canceled, closed, created, deleted, hidden, updated) */
</script>
<tr>
{#if obj != null && typeof obj == 'object'}
{#each Object.entries(obj) as [obj_prop_name, obj_prop_value]}
<!-- NEED TO ADD A CHECK IF:
NOTE:
NOTE:
obj.id_random and obj.name then replace the ID field column with a link using obj.name
This should probably go outside/before this tr loop.
NOTE:
NOTE:
-->
{#if obj_prop_name.endsWith('_id_random') || obj_prop_name == 'for_type' || obj_prop_name == 'for_id'}
{#if row_header}
<th data-obj_type={primary_obj_li_type} data-obj_prop_name={obj_prop_name} on:click={() => primary_obj_li_type=obj_prop_name.replace('_id_random', '')}>
{ae_util.set_obj_prop_display_name({prop_name: obj_prop_name, obj_type: primary_obj_li_type})}
</th>
{:else}
<td
data-obj_type={primary_obj_li_type}
data-obj_prop_name={obj_prop_name}
on:click={() => {
slct_obj_type=obj_prop_name.replace('_id_random', '');
slct_obj_id=obj_prop_value;
}}
on:keypress={() => {
slct_obj_type=obj_prop_name.replace('_id_random', '');
slct_obj_id=obj_prop_value;
}}
>
<!-- {obj_prop_value} -->
<!-- {#if (obj_prop_value && obj_prop_value.length > 25)}
{obj_prop_value.substring(0,25)}
{:else} -->
{#if obj_prop_value}
<a href="/{ae_util.return_obj_type_path({obj_type_prop_name: obj_prop_name})}/{obj_prop_value}">
{obj_prop_value.substring(0,25)}
</a>
{:else}
<!-- {obj_prop_value} -->
<span class="fs_smaller">-- None --</span>
{/if}
</td>
{/if}
{:else if obj_prop_name.endsWith('[URL]')}
{#if row_header}
<th data-obj_type={primary_obj_li_type} data-obj_prop_name={obj_prop_name} on:click={() => primary_obj_li_type=obj_prop_name.replaceAll('[URL]', '')}>
{ae_util.set_obj_prop_display_name({prop_name: obj_prop_name.replaceAll('[URL]', ''), obj_type: primary_obj_li_type})}
</th>
{:else}
<td
data-obj_type={primary_obj_li_type}
data-obj_prop_name={obj_prop_name}
on:click={() => {
slct_obj_type=obj_prop_name.replaceAll('[URL]', '');
slct_obj_id=obj_prop_value;
}}
on:keypress={() => {
slct_obj_type=obj_prop_name.replaceAll('[URL]', '');
slct_obj_id=obj_prop_value;
}}
>
<a href="{obj_prop_value}">{obj_prop_value}</a>
</td>
{/if}
{:else}
{#if row_header}
<th data-obj_type={primary_obj_li_type} data-obj_prop_name={obj_prop_name}>
{ae_util.set_obj_prop_display_name({prop_name: obj_prop_name, obj_type: primary_obj_li_type})}
</th>
{:else}
<td data-obj_type={primary_obj_li_type} data-obj_prop_name={obj_prop_name}>
{#if (obj_prop_value)}
{#if (obj_prop_value && obj_prop_value.length > 25)}
{obj_prop_value.substring(0,25)} ...
{:else}
{obj_prop_value}
{/if}
{:else}
<span class="fs_smaller">-- None --</span>
{/if}
</td>
{/if}
{/if}
<!-- <td data-obj_type={primary_obj_li_type} data-obj_prop_name={obj_prop_name}>{obj_prop_value}</td> -->
{/each}
{:else}
-- Not Set --
{/if}
</tr>
<style lang="postcss">
</style>

View File

@@ -0,0 +1,543 @@
<script lang="ts">
// *** Import Svelte core
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
// import 'html5-qrcode';
import {Html5Qrcode, Html5QrcodeScannerState, Html5QrcodeSupportedFormats} from 'html5-qrcode';
// *** Import Aether core variables and functions
import { api } from '$lib/api';
import { ae_api } from '$lib/ae_stores';
// *** Import Aether core components
// import Element_input from './element_input.svelte';
// import ae from '/element_input.svelte';
// import Input_element from '/element_input.svelte';
// *** Import Aether module variables and functions
// *** Import Aether module components
// *** Export/Exposed variables and functions for component
export let start_qr_scanner: boolean = true;
export let show_pause_btn: boolean = false; // pause and resume buttons
export let show_qr_manual_text_entry_option: boolean = false;
export let show_qr_manual_badge_id_entry_option: boolean = false;
export let show_qr_scan_result: boolean = true;
export let qr_fps = 15;
export let qr_viewfinder_width = 275; // 275 seems good... Need to not let the this be larger than the container which changes based on the width of the screen/window.
export let qr_facing_mode = 'environment'; // environment, user, { exact: 'environment'}, { exact: 'user'}
// *** Set initial variables
let scanning_status: string = 'not_started';
let qr_scan_result: null|string = null;
let qr_found_text: null|string = null;
let qr_entered_text: null|string = null;
let qr_entered_badge_id: null|string = null;
let show_qr_manual_entry: null|boolean = null;
let disable_submit_badge_id_btn: boolean = true;
let user_media_status = 'not_requested';
// let max_results: number = 50;
const dispatch = createEventDispatcher();
let html5_qr_code: any|null|string = null;
// let html5_qr_code = new Html5Qrcode(
// 'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
// );
// let qr_scan_cfg = { fps: 10, qrbox: 400 }; // default was 250 and using 300 when 600px
let qr_scan_cfg = { fps: qr_fps, qrbox: qr_viewfinder_width }; // 275 seems good... Need to not let the this be larger than the container which changes based on the width of the screen/window.
// let mounted = false;
onMount(() => {
console.log('** Element Mounted: ** QR Scanner');
// NOTE: We only want to trigger the scanning to start after the page has fully loaded.
navigator.mediaDevices.getUserMedia({video: true})
.then(successCallback, errorCallback);
// NOTE: This can only be done after the page has fully loaded.
// if (start_qr_scanner) {
// handle_start_qr_scanning();
// }
});
onDestroy(async () => {
console.log('** Element Destroyed: ** QR Scanner');
qr_scan_result = null;
qr_found_text = null;
await handle_stop_qr_scanning();
});
var successCallback = function(error: any) {
console.log('Camera access allowed');
user_media_status = 'allowed';
// let subject = 'Camera Access Allowed';
// let message = error;
// send_init_confirm_email(subject, message);
dispatch('qr_camera', {
status: 'allowed',
});
// NOTE: This can only be done after the page has fully loaded.
if (start_qr_scanner) {
handle_start_qr_scanning();
}
};
var errorCallback = function(error: any) {
if (error.name == 'NotAllowedError') {
console.log('Camera access not allowed!');
user_media_status = 'denied';
// let subject = 'Camera Access Denied';
// let message = error;
// send_init_confirm_email(subject, message);
dispatch('qr_camera', {
status: 'denied',
});
}
};
// $: if (mounted && start_qr_scanner) {
// console.log('START QR SCANNING');
// handle_start_qr_scanning();
// } else if (mounted && !start_qr_scanner) {
// console.log('STOP QR SCANNING');
// handle_stop_qr_scanning();
// }
async function handle_start_qr_scanning() {
console.log('*** handle_start_qr_scanning() ***');
if (user_media_status == 'denied') {
console.log('Camera access not allowed!');
return;
} else if (user_media_status == 'not_requested') {
console.log('Camera access not requested yet!');
return;
}
qr_scan_result = null;
qr_found_text = null;
if (html5_qr_code) {
console.log('html5_qr_code object found. Clearing and creating new Html5Qrcode...');
// html5_qr_code.clear();
// document.getElementById('qr_scanner_viewfinder').classList.remove('d_none');
html5_qr_code = new Html5Qrcode(
'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
);
} else {
console.log('html5_qr_code not found. Creating new Html5Qrcode...');
html5_qr_code = new Html5Qrcode(
'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
);
}
if (html5_qr_code.getState() == Html5QrcodeScannerState.NOT_STARTED) {
// console.log('Scanner is not started');
return await html5_qr_code.start({ facingMode: qr_facing_mode }, qr_scan_cfg, handle_qr_scan_success, handle_qr_scan_error)
.then((ignore: any) => {
console.log('Scanning has started');
scanning_status = 'scanning';
// let subject = 'QR Scanning Started';
// let message = ignore;
// send_init_confirm_email(subject, message);
return true;
}).catch((err) => {
console.log('There was an error while trying to start the QR scanner');
scanning_status = 'start_error';
let subject = 'QR Scanning Start Error';
let message = err;
send_init_confirm_email(subject, message);
return false;
});
} else {
console.log('Scanner is already started');
return;
}
}
function handle_pause_qr_scanning() {
if (html5_qr_code && html5_qr_code.getState() != Html5QrcodeScannerState.SCANNING) {
console.log('Scanner is not scanning!');
return;
}
html5_qr_code.pause();
scanning_status = 'paused';
}
function handle_resume_qr_scanning() {
if (html5_qr_code && html5_qr_code.getState() != Html5QrcodeScannerState.PAUSED) {
console.log('Scanner is not paused!');
return;
}
document.getElementById('qr_scanner_viewfinder').classList.remove('d_none');
html5_qr_code.resume();
scanning_status = 'scanning';
}
async function handle_stop_qr_scanning() {
start_qr_scanner = false;
if (!html5_qr_code) {
console.log('html5_qr_code object found. Nothing to stop?');
return false;
}
let state = html5_qr_code.getState();
console.log('html5_qr_code state:', state);
if (state == Html5QrcodeScannerState.NOT_STARTED) {
console.log('Scanner is not started');
return;
}
if (state == Html5QrcodeScannerState.PAUSED || state == Html5QrcodeScannerState.SCANNING) {
console.log('Scanner is not started');
await html5_qr_code.stop()
scanning_status = 'not_started';
return;
}
await html5_qr_code.clear();
return true;
// html5_qr_code.pause();
// return html5_qr_code.stop()
// .then((ignore) => {
// console.log('Scanning has stopped');
// // document.getElementById('qr_scanner_viewfinder').classList.add('d_none');
// scanning_status = 'not_started';
// }).then((ignore) => {
// // html5_qr_code = null;
// // html5_qr_code.clear();
// }).catch((err) => {
// console.log('There was an error while trying to stop the scanning');
// return false;
// });
// html5_qr_code = null;
}
// Callback function for QrcodeSuccessCallback (decodedText: string, result: Html5QrcodeResult)
function handle_qr_scan_success(decoded_text, decoded_result) {
console.log('*** handle_qr_scan_success() ***');
console.log(`QR scanned = ${decoded_text}`, decoded_result);
qr_scan_result = decoded_text; // NOTE: decoded_result is not currently used by html5-qrcode
qr_found_text = decoded_text;
dispatch('qr_scan_result', {
result: qr_scan_result, // This text will need to be parsed to get more info.
text: qr_found_text, // This text will need to be parsed to get more info.
entry_method: 'QR',
});
// handle_pause_qr_scanning();
handle_stop_qr_scanning();
}
// Callback function for QrcodeErrorCallback (errorMessage: string, error: Html5QrcodeError)
// NOTE: Most of the time this is normal and not an actual error. It just did not find something to scan.
function handle_qr_scan_error(qr_error_message, qr_code_error) {
// console.log('*** handle_qr_scan_error() ***');
if (qr_code_error.type) {
console.log(`Error scanning code = ${qr_error_message}`, qr_code_error);
return;
}
}
$: if ( qr_entered_badge_id && qr_entered_badge_id.length >= 11 && qr_entered_badge_id && qr_entered_badge_id.length <= 14) {
disable_submit_badge_id_btn = false;
} else {
disable_submit_badge_id_btn = true;
}
function handle_qr_manual_entry() {
console.log('*** handle_qr_manual_entry() ***');
if (qr_entered_text) {
console.log(`QR entered text = ${qr_entered_text}`);
} else if (qr_entered_badge_id) {
console.log(`QR entered badge ID = ${qr_entered_badge_id}`);
qr_entered_text = `OBJ:ot:event_badge,oi:${qr_entered_badge_id}`;
console.log(`Parse to proper QR badge ID = ${qr_entered_text}`);
}
// html5_qr_code.stop().then((ignore) => {
// console.log('Scanning has stopped');
// document.getElementById('qr_scanner_viewfinder').classList.add('d_none');
// }).catch((err) => {
// console.log('There was an error while trying to stop the scanning');
// });
qr_scan_result = qr_entered_text;
dispatch('qr_scan_result', {
result: qr_scan_result,
entry_method: 'manual',
});
qr_scan_result = null;
qr_entered_text = null;
}
function send_init_confirm_email(subject, message) {
console.log(`*** send_init_confirm_email() *** ${subject}`);
let to_email = 'scott.idem+skdev@oneskyit.com';
// let origin_url = encodeURI(`${data.url.origin}`);
let full_subject = `${subject} Aether QR Scanner Debugging`;
let body_html = `
<div>Scott,
<p>This is an automatic debug email from the Aether QR scanner.</p>
</div>
<br>
<div>
Message:<br>
<pre>
${JSON.stringify(message)}
</pre>
</div>
`;
api.send_email({
api_cfg: $ae_api,
from_email: 'noreply+ae_qr_debug@oneskyit.com',
from_name: 'AE QR Debug',
to_email: to_email,
subject: full_subject,
body_html: body_html,
});
}
</script>
<section
class="ae_element qr_scanner border-2 border-slate-500/10 space-y-2 flex flex-col gap-1 justify-center items-center min-w-full max-w-full"
class:not_started={scanning_status == 'not_started'}
class:paused={scanning_status == 'paused'}
class:scanning={scanning_status == 'scanning'}
>
<!-- <header>
<h2>QR Scanner</h2>
</header> -->
<!-- <fieldset class=""> -->
<!-- <legend class="d_none">QR Scanner:</legend> -->
<div
class="ae_container qr_scanning_container"
>
<div
class="ae_options m-1"
>
{#if scanning_status == 'not_started' }
<button on:click={handle_start_qr_scanning} class="btn btn-lg variant-soft-primary btn_start"><span class="fas fa-qrcode mx-1"></span> Start Scanning</button>
<span class="loading-text">
Scanning stopped
</span>
{:else if scanning_status == 'paused' && show_pause_btn}
<button on:click={handle_resume_qr_scanning} class="btn btn-md variant-soft-primary btn_resume"><span class="fas fa-play"></span> Resume</button>
<span>Scanning paused</span>
{:else if scanning_status == 'scanning'}
<button on:click={handle_stop_qr_scanning} class="btn btn-md variant-soft-secondary btn_stop">
<span class="fas fa-crosshairs fa-spin opacity-50 m-1"></span>
<!-- <span class="fas fa-stop-circle m-1"></span> -->
Stop
</button>
{#if show_pause_btn}
<button on:click={handle_pause_qr_scanning} class="btn btn-lg variant-soft-secondary btn_pause"><span class="fas fa-pause-circle"></span> Pause</button>
{/if}
<!-- <span>Scanning for QR code...</span> -->
<!-- <div class="modal-loading"> -->
<!-- <span class="fas fa-crosshairs fa-spin opacity-50"></span> -->
<span class="loading-text">
Scanning for QR code...
</span>
<!-- </div> -->
{/if}
</div>
<div id="qr_scanner_viewfinder" class="qr_scanner_viewfinder grow flex flex-col justify-center items-center" style=""></div> <!-- width: 600px -->
</div>
{#if show_qr_manual_text_entry_option}
<div class="ae_container qr_manual_entry text_entry">
{#if show_qr_manual_entry}
<label for="entered_text" class="">Enter text</label>
<input type="text" name="entered_text" id="entered_text" bind:value="{qr_entered_text}">
<button on:click={handle_qr_manual_entry} class="btn btn-md variant-soft-warning"><span class="fas fa-paper-plane"></span> Submit Text</button>
<div class="search_by_text">
<input type='text' placeholder="Name or Email" label="Name or Email" value={search_query_str} focus={true} on:oninput={handle_oninput_search_query_str} />
</div>
{:else}
<button on:click={() => show_qr_manual_entry=true} class="btn btn-md variant-soft-warning"><span class="fas fa-keyboard"></span> Enter Text</button>
{/if}
</div>
{/if}
{#if show_qr_manual_badge_id_entry_option}
<div class="ae_container qr_manual_entry badge_id_entry">
{#if show_qr_manual_entry}
<form on:submit|preventDefault={() => handle_qr_manual_entry} class="flex">
<!-- <label for="entered_badge_id" class="">Enter badge ID</label>
<input type="text" name="entered_badge_id" id="entered_badge_id" bind:value="{qr_entered_badge_id}"> -->
<input
bind:value="{qr_entered_badge_id}"
type="text"
name="entered_badge_id"
id="entered_badge_id"
required
placeholder="Enter Badge ID"
class="input max-w-52"
/>
<button
type="submit"
on:click={handle_qr_manual_entry}
disabled={disable_submit_badge_id_btn}
class="btn btn-md variant-ghost-primary m-1"
class:btn_default={disable_submit_badge_id_btn}
class:btn_primary={!disable_submit_badge_id_btn}
>
<span class="fas fa-paper-plane mx-1"></span> Submit Badge ID
</button>
</form>
{:else}
<button on:click={() => show_qr_manual_entry=true} class="btn btn-md variant-soft-secondary m-1"><span class="fas fa-keyboard mx-1"></span> Enter Badge ID</button>
{/if}
</div>
{/if}
{#if show_qr_scan_result && qr_scan_result}
<div class="ae_container qr_scan_result">
<span class="label">Raw Result:</span>
<span id="qr_scan_result_value" class="value">{qr_scan_result}</span>
</div>
{/if}
<!-- </fieldset> -->
</section>
<style>
.not_started {
background-color: hsla(0, 100%, 75%, 0.3);
border-color: hsla(0, 100%, 75%, 0.6);
}
.paused {
background-color: hsla(60, 100%, 75%, 0.3);
border-color: hsla(60, 100%, 75%, 0.6);
}
.scanning {
background-color: hsla(120, 100%, 75%, 0.3);
border-color: hsla(120, 100%, 75%, 0.6);
}
.qr_scanner {
/* outline: solid thin pink; */
max-width: 100vw;
/* overflow-x: scroll; */
display: flex;
flex-direction: column;
/* flex-wrap: wrap; */
justify-content: flex-start;
align-items: center; /* center */
align-content: stretch;
}
.ae_element.qr_scanner div.qr_scanner_viewfinder {
/* max-width: 100vw; */
/* contain: content; */
/* contain: contain; */
}
.qr_scanner .qr_scanner_viewfinder {
/* outline: dashed medium blue; */
min-width: 400px;
width: 100%;
/* max-width: 100%; */
max-width: 500px;
/* max-width: 100vw; */
/* outline: solid thin red; */
contain: contain;
overflow-x: scroll;
}
@media (max-width: 767px) {
.qr_scanner .qr_scanner_viewfinder {
/* outline: dashed medium red; */
min-width: 80vw;
/* width: 100%; */
/* max-width: 100%; */
/* max-width: 450px; */
max-width: 100vw;
margin: 0;
padding: 0;
}
}
</style>

View File

@@ -0,0 +1,683 @@
<script lang="ts">
// *** Import Svelte core
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
// import 'html5-qrcode';
import {Html5Qrcode, Html5QrcodeScannerState, Html5QrcodeSupportedFormats} from 'html5-qrcode';
// *** Import Aether core variables and functions
import { api } from '$lib/api';
import { ae_api } from '$lib/ae_stores';
// *** Import Aether core components
// import Element_input from './element_input.svelte';
// import ae from '/element_input.svelte';
// import Input_element from '/element_input.svelte';
// *** Import Aether module variables and functions
// *** Import Aether module components
// *** Export/Exposed variables and functions for component
export let start_qr_scanner: boolean = true;
export let show_pause_btn: boolean = false; // pause and resume buttons
export let show_qr_manual_text_entry_option: boolean = false;
export let show_qr_manual_badge_id_entry_option: boolean = false;
export let show_qr_scan_result: boolean = true;
export let qr_fps = 10;
export let qr_viewfinder_width = 275; // 275 seems good... Need to not let the this be larger than the container which changes based on the width of the screen/window.
export let qr_facing_mode = 'environment'; // environment, user, { exact: 'environment'}, { exact: 'user'}
// *** Set initial variables
let scanning_status: string = 'not_started';
let qr_scan_result: null|string = null;
let qr_found_text: null|string = null;
let qr_entered_text: null|string = null;
let qr_entered_badge_id: null|string = null;
let show_qr_manual_entry: null|boolean = null;
let disable_submit_badge_id_btn: boolean = true;
let user_media_status = 'not_requested';
let debug_comment: string = 'Debugging QR Scanner';
let debug_info: any;
// let max_results: number = 50;
const dispatch = createEventDispatcher();
let html5_qr_code: any|null|string = null;
// let html5_qr_code = new Html5Qrcode(
// 'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
// );
// let qr_scan_cfg = { fps: 10, qrbox: 400 }; // default was 250 and using 300 when 600px
// let qr_scan_cfg = { fps: qr_fps, qrbox: qr_viewfinder_width }; // 275 seems good... Need to not let the this be larger than the container which changes based on the width of the screen/window.
let qr_scan_cfg = {};
// let mounted = false;
onMount(() => {
console.log('** Element Mounted: ** QR Scanner');
console.log('** Element Mounted: ** QR Scanner - getUserMedia');
var constraints = {
video: false,
audio: false
}
navigator.mediaDevices.getUserMedia(constraints)
.then(get_user_media_success, get_user_media_error);
// navigator.mediaDevices.getUserMedia(constraints)
// .then(get_user_media_success, get_user_media_error)
// .catch(function(err) {
// //log to console first
// console.log(err); /* handle the error */
// if (err.name == "NotFoundError" || err.name == "DevicesNotFoundError") {
// //required track is missing
// } else if (err.name == "NotReadableError" || err.name == "TrackStartError") {
// //webcam or mic are already in use
// } else if (err.name == "OverconstrainedError" || err.name == "ConstraintNotSatisfiedError") {
// //constraints can not be satisfied by avb. devices
// } else if (err.name == "NotAllowedError" || err.name == "PermissionDeniedError") {
// //permission denied in browser
// } else if (err.name == "TypeError" || err.name == "TypeError") {
// //empty constraints object
// } else {
// //other errors
// }
// });
// navigator.mediaDevices.getUserMedia({video: true})
// .then(get_user_media_success, get_user_media_error);
// console.log('** Element Mounted: ** QR Scanner - setTimeout 750ms then getUserMedia');
// Wait 250ms for everything to fully load
// setTimeout(() => {
// console.log('** Element Mounted: ** QR Scanner - inside setTimeout 750ms');
// navigator.mediaDevices.getUserMedia({video: true})
// .then(get_user_media_success, get_user_media_error);
// }, 750);
// console.log('** Element Mounted: ** QR Scanner - setTimeout end 750ms');
// NOTE: This can only be done after the page has fully loaded.
// if (start_qr_scanner) {
// handle_start_qr_scanning();
// }
});
onDestroy(async () => {
console.log('** Element Destroyed: ** QR Scanner');
qr_scan_result = null;
qr_found_text = null;
await handle_stop_qr_scanning();
});
var get_user_media_success = function(error: any) {
console.log('Camera access allowed');
user_media_status = 'allowed';
debug_comment = 'Camera Access Allowed';
debug_info = JSON.stringify(error);
// if (html5_qr_code) {
// console.log('html5_qr_code object found. Clearing and creating new Html5Qrcode...');
// debug_info = 'html5_qr_code object found. Clearing and creating new Html5Qrcode...';
// html5_qr_code.clear();
// // document.getElementById('qr_scanner_viewfinder').classList.remove('d_none');
// } else {
// console.log('html5_qr_code not found. Creating new Html5Qrcode...');
// debug_info = 'html5_qr_code not found. Creating new Html5Qrcode...';
// }
html5_qr_code = new Html5Qrcode(
'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
);
debug_comment = 'Html5Qrcode created';
debug_info = 'new Html5Qrcode for element id=qr_scanner_viewfinder QR_CODE';
if (start_qr_scanner) {
// console.log('** Element Mounted: ** QR Scanner - getUserMedia in setTimeout');
setTimeout(() => {
console.log('** Element Mounted: ** QR Scanner - setTimeout');
console.log('Ready to start QR scanning!');
debug_info = 'Ready to start QR scanning!';
handle_start_qr_scanning();
}, 2500);
// console.log('** Element Mounted: ** QR Scanner - setTimeout end');
}
// let subject = 'Camera Access Allowed';
// let message = error;
// send_init_confirm_email(subject, message);
console.log('Dispatching qr_camera');
debug_info = 'Dispatching qr_camera';
dispatch('qr_camera', {
status: 'allowed',
});
// NOTE: This can only be done after the page has fully loaded.
// if (start_qr_scanner) {
// handle_start_qr_scanning();
// }
};
var get_user_media_error = function(error: any) {
if (error.name == 'NotAllowedError') {
console.log('Camera access not allowed!');
user_media_status = 'denied';
debug_comment = 'Camera Access Denied';
debug_info = JSON.stringify(error);
// alert('Error trying to start camera');
// alert(error);
let subject = 'Camera Access Denied';
let message = error;
send_init_confirm_email(subject, message);
dispatch('qr_camera', {
status: 'denied',
});
}
};
// $: if (start_qr_scanner && user_media_status == 'allowed' && (scanning_status == 'not_started' || scanning_status == 'paused')) {
// console.log('START QR SCANNING');
// handle_start_qr_scanning();
// } else {
// // console.log('STOP QR SCANNING');
// // handle_stop_qr_scanning();
// }
// $: if (mounted && start_qr_scanner) {
// console.log('START QR SCANNING');
// handle_start_qr_scanning();
// } else if (mounted && !start_qr_scanner) {
// console.log('STOP QR SCANNING');
// handle_stop_qr_scanning();
// }
async function handle_start_qr_scanning() {
console.log('*** handle_start_qr_scanning() ***');
if (user_media_status == 'denied') {
console.log('Camera access not allowed!');
return;
} else if (user_media_status == 'not_requested') {
console.log('Camera access not requested yet!');
return;
} else if (user_media_status == 'allowed') {
console.log('Camera access allowed!');
debug_info = 'Camera access allowed!';
} else {
console.log('Camera access status unknown! This should not happen?');
debug_info = 'Camera access status unknown! This should not happen?';
return;
}
qr_scan_result = null;
qr_found_text = null;
debug_comment = 'Starting QR Scanning...';
// if (html5_qr_code) {
// console.log('html5_qr_code object found. Clearing and creating new Html5Qrcode...');
// debug_info = 'html5_qr_code object found. Clearing and creating new Html5Qrcode...';
// html5_qr_code.clear();
// // document.getElementById('qr_scanner_viewfinder').classList.remove('d_none');
// html5_qr_code = new Html5Qrcode(
// 'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
// );
// } else {
// console.log('html5_qr_code not found. Creating new Html5Qrcode...');
// debug_info = 'html5_qr_code not found. Creating new Html5Qrcode...';
// html5_qr_code = new Html5Qrcode(
// 'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
// );
// }
debug_info = 'Check the state and start if not started...';
let current_state = await html5_qr_code.getState()
if (current_state == Html5QrcodeScannerState.NOT_STARTED) {
// console.log('Scanner is not started');
debug_info = 'Waiting... Scanner is not started';
setTimeout(() => {
debug_info = 'Waited long enough! Starting for real!';
html5_qr_code.start({ facingMode: qr_facing_mode }, qr_scan_cfg, handle_qr_scan_success, handle_qr_scan_error)
.then((ignore: any) => {
console.log('Scanning has started');
scanning_status = 'scanning';
debug_info = 'Scanning has started';
// let subject = 'QR Scanning Started';
// let message = ignore;
// send_init_confirm_email(subject, message);
return true;
}).catch((err) => {
console.log('There was an error while trying to start the QR scanner');
scanning_status = 'start_error';
debug_comment = 'Error starting scanner after getState() NOT_STARTED';
debug_info = 'Error starting scanner: ' + JSON.stringify(err);
// let subject = 'QR Scanning Start Error';
// let message = err;
// send_init_confirm_email(subject, message);
// Error getting userMedia, error = NotReadableError: Could not start video source
return false;
});
}, 750);
debug_info = 'Waiting...?';
} else {
console.log('Scanner is already started');
debug_info = 'Scanner is already started';
return;
}
}
function handle_pause_qr_scanning() {
if (html5_qr_code && html5_qr_code.getState() != Html5QrcodeScannerState.SCANNING) {
console.log('Scanner is not scanning!');
return;
}
html5_qr_code.pause();
scanning_status = 'paused';
}
function handle_resume_qr_scanning() {
if (html5_qr_code && html5_qr_code.getState() != Html5QrcodeScannerState.PAUSED) {
console.log('Scanner is not paused!');
return;
}
document.getElementById('qr_scanner_viewfinder').classList.remove('d_none');
html5_qr_code.resume();
scanning_status = 'scanning';
}
async function handle_stop_qr_scanning() {
start_qr_scanner = false;
if (!html5_qr_code) {
console.log('html5_qr_code object found. Nothing to stop?');
return false;
}
let state = html5_qr_code.getState();
console.log('html5_qr_code state:', state);
if (state == Html5QrcodeScannerState.NOT_STARTED) {
console.log('Scanner is not started');
return;
}
if (state == Html5QrcodeScannerState.PAUSED || state == Html5QrcodeScannerState.SCANNING) {
console.log('Scanner is not started');
await html5_qr_code.stop()
scanning_status = 'not_started';
return;
}
await html5_qr_code.clear();
return true;
// html5_qr_code.pause();
// return html5_qr_code.stop()
// .then((ignore) => {
// console.log('Scanning has stopped');
// // document.getElementById('qr_scanner_viewfinder').classList.add('d_none');
// scanning_status = 'not_started';
// }).then((ignore) => {
// // html5_qr_code = null;
// // html5_qr_code.clear();
// }).catch((err) => {
// console.log('There was an error while trying to stop the scanning');
// return false;
// });
// html5_qr_code = null;
}
// Callback function for QrcodeSuccessCallback (decodedText: string, result: Html5QrcodeResult)
function handle_qr_scan_success(decoded_text, decoded_result) {
console.log('*** handle_qr_scan_success() ***');
console.log(`QR scanned = ${decoded_text}`, decoded_result);
qr_scan_result = decoded_text; // NOTE: decoded_result is not currently used by html5-qrcode
qr_found_text = decoded_text;
dispatch('qr_scan_result', {
result: qr_scan_result, // This text will need to be parsed to get more info.
text: qr_found_text, // This text will need to be parsed to get more info.
entry_method: 'QR',
});
// handle_pause_qr_scanning();
handle_stop_qr_scanning();
}
// Callback function for QrcodeErrorCallback (errorMessage: string, error: Html5QrcodeError)
// NOTE: Most of the time this is normal and not an actual error. It just did not find something to scan.
function handle_qr_scan_error(qr_error_message, qr_code_error) {
// console.log('*** handle_qr_scan_error() ***');
if (qr_code_error.type) {
console.log(`Error scanning code = ${qr_error_message}`, qr_code_error);
return;
}
}
$: if ( qr_entered_badge_id && qr_entered_badge_id.length >= 11 && qr_entered_badge_id && qr_entered_badge_id.length <= 14) {
disable_submit_badge_id_btn = false;
} else {
disable_submit_badge_id_btn = true;
}
function handle_qr_manual_entry() {
console.log('*** handle_qr_manual_entry() ***');
if (qr_entered_text) {
console.log(`QR entered text = ${qr_entered_text}`);
} else if (qr_entered_badge_id) {
console.log(`QR entered badge ID = ${qr_entered_badge_id}`);
qr_entered_text = `OBJ:ot:event_badge,oi:${qr_entered_badge_id}`;
console.log(`Parse to proper QR badge ID = ${qr_entered_text}`);
}
// html5_qr_code.stop().then((ignore) => {
// console.log('Scanning has stopped');
// document.getElementById('qr_scanner_viewfinder').classList.add('d_none');
// }).catch((err) => {
// console.log('There was an error while trying to stop the scanning');
// });
qr_scan_result = qr_entered_text;
dispatch('qr_scan_result', {
result: qr_scan_result,
entry_method: 'manual',
});
qr_scan_result = null;
qr_entered_text = null;
}
function send_init_confirm_email(subject, message) {
console.log(`*** send_init_confirm_email() *** ${subject}`);
let to_email = 'scott.idem+skdev@oneskyit.com';
// let origin_url = encodeURI(`${data.url.origin}`);
let full_subject = `${subject} Aether QR Scanner Debugging`;
let body_html = `
<div>Scott,
<p>This is an automatic debug email from the Aether QR scanner.</p>
</div>
<br>
<div>
Message:<br>
<pre>
${JSON.stringify(message)}
</pre>
</div>
`;
api.send_email({
api_cfg: $ae_api,
from_email: 'noreply+ae_qr_debug@oneskyit.com',
from_name: 'AE QR Debug',
to_email: to_email,
subject: full_subject,
body_html: body_html,
});
}
</script>
<section
class="ae_element qr_scanner border-2 border-slate-500/10 space-y-2 flex flex-col gap-1 justify-center items-center min-w-full max-w-full"
class:not_started={scanning_status == 'not_started'}
class:paused={scanning_status == 'paused'}
class:scanning={scanning_status == 'scanning'}
>
<!-- <header>
<h2>QR Scanner</h2>
</header> -->
<!-- <fieldset class=""> -->
<!-- <legend class="d_none">QR Scanner:</legend> -->
<div
class="ae_container qr_scanning_container"
>
<div
class="ae_options m-1"
>
{#if scanning_status == 'not_started' }
<button on:click={handle_start_qr_scanning} class="btn btn-lg variant-soft-primary btn_start"><span class="fas fa-qrcode mx-1"></span> Start Scanning</button>
<span class="loading-text">
Scanning stopped
</span>
{:else if scanning_status == 'paused' && show_pause_btn}
<button on:click={handle_resume_qr_scanning} class="btn btn-md variant-soft-primary btn_resume"><span class="fas fa-play"></span> Resume</button>
<span>Scanning paused</span>
{:else if scanning_status == 'scanning'}
<button on:click={handle_stop_qr_scanning} class="btn btn-md variant-soft-secondary btn_stop">
<span class="fas fa-crosshairs fa-spin opacity-50 m-1"></span>
<!-- <span class="fas fa-stop-circle m-1"></span> -->
Stop
</button>
{#if show_pause_btn}
<button on:click={handle_pause_qr_scanning} class="btn btn-lg variant-soft-secondary btn_pause"><span class="fas fa-pause-circle"></span> Pause</button>
{/if}
<!-- <span>Scanning for QR code...</span> -->
<!-- <div class="modal-loading"> -->
<!-- <span class="fas fa-crosshairs fa-spin opacity-50"></span> -->
<span class="loading-text">
Scanning for QR code...
</span>
<!-- </div> -->
{/if}
</div>
<div id="qr_scanner_viewfinder" class="qr_scanner_viewfinder grow flex flex-col justify-center items-center" style=""></div> <!-- width: 600px -->
</div>
{#if show_qr_manual_text_entry_option}
<div class="ae_container qr_manual_entry text_entry">
{#if show_qr_manual_entry}
<label for="entered_text" class="">Enter text</label>
<input type="text" name="entered_text" id="entered_text" bind:value="{qr_entered_text}">
<button on:click={handle_qr_manual_entry} class="btn btn-md variant-soft-warning"><span class="fas fa-paper-plane"></span> Submit Text</button>
<div class="search_by_text">
<input type='text' placeholder="Name or Email" label="Name or Email" value={search_query_str} focus={true} on:oninput={handle_oninput_search_query_str} />
</div>
{:else}
<button on:click={() => show_qr_manual_entry=true} class="btn btn-md variant-soft-warning"><span class="fas fa-keyboard"></span> Enter Text</button>
{/if}
</div>
{/if}
{#if show_qr_manual_badge_id_entry_option}
<div class="ae_container qr_manual_entry badge_id_entry">
{#if show_qr_manual_entry}
<form on:submit|preventDefault={() => handle_qr_manual_entry} class="flex">
<!-- <label for="entered_badge_id" class="">Enter badge ID</label>
<input type="text" name="entered_badge_id" id="entered_badge_id" bind:value="{qr_entered_badge_id}"> -->
<input
bind:value="{qr_entered_badge_id}"
type="text"
name="entered_badge_id"
id="entered_badge_id"
required
placeholder="Enter Badge ID"
class="input max-w-52"
/>
<button
type="submit"
on:click={handle_qr_manual_entry}
disabled={disable_submit_badge_id_btn}
class="btn btn-md variant-ghost-primary m-1"
class:btn_default={disable_submit_badge_id_btn}
class:btn_primary={!disable_submit_badge_id_btn}
>
<span class="fas fa-paper-plane mx-1"></span> Submit Badge ID
</button>
</form>
{:else}
<button on:click={() => show_qr_manual_entry=true} class="btn btn-md variant-soft-secondary m-1"><span class="fas fa-keyboard mx-1"></span> Enter Badge ID</button>
{/if}
</div>
{/if}
{#if show_qr_scan_result && qr_scan_result}
<div class="ae_container qr_scan_result">
<span class="label">Raw Result:</span>
<span id="qr_scan_result_value" class="value">{qr_scan_result}</span>
</div>
{/if}
{debug_comment ?? 'Debugging QR Scanner'}
{#if debug_info}
<div class="ae_container debug_info">
<span class="label">Debug Info:</span>
<span class="value">{debug_info}</span>
</div>
{/if}
<!-- </fieldset> -->
</section>
<style>
.not_started {
background-color: hsla(0, 100%, 75%, 0.3);
border-color: hsla(0, 100%, 75%, 0.6);
}
.paused {
background-color: hsla(60, 100%, 75%, 0.3);
border-color: hsla(60, 100%, 75%, 0.6);
}
.scanning {
background-color: hsla(120, 100%, 75%, 0.3);
border-color: hsla(120, 100%, 75%, 0.6);
}
.qr_scanner {
/* outline: solid thin pink; */
max-width: 100vw;
/* overflow-x: scroll; */
display: flex;
flex-direction: column;
/* flex-wrap: wrap; */
justify-content: flex-start;
align-items: center; /* center */
align-content: stretch;
}
.ae_element.qr_scanner div.qr_scanner_viewfinder {
/* max-width: 100vw; */
/* contain: content; */
/* contain: contain; */
}
.qr_scanner .qr_scanner_viewfinder {
/* outline: dashed medium blue; */
min-width: 400px;
width: 100%;
/* max-width: 100%; */
max-width: 500px;
/* max-width: 100vw; */
/* outline: solid thin red; */
contain: contain;
overflow-x: scroll;
}
@media (max-width: 767px) {
.qr_scanner .qr_scanner_viewfinder {
/* outline: dashed medium red; */
min-width: 80vw;
/* width: 100%; */
/* max-width: 100%; */
/* max-width: 450px; */
max-width: 100vw;
margin: 0;
padding: 0;
}
}
</style>

View File

@@ -0,0 +1,641 @@
<script lang="ts">
// *** Import Svelte core
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
// import 'html5-qrcode';
import {Html5Qrcode, Html5QrcodeScannerState, Html5QrcodeSupportedFormats} from 'html5-qrcode';
// *** Import Aether core variables and functions
import { api } from '$lib/api';
import { ae_api } from '$lib/ae_stores';
// *** Import Aether core components
// import Element_input from './element_input.svelte';
// import ae from '/element_input.svelte';
// import Input_element from '/element_input.svelte';
// *** Import Aether module variables and functions
// *** Import Aether module components
// *** Export/Exposed variables and functions for component
export let start_qr_scanner: boolean = true;
export let show_pause_btn: boolean = false; // pause and resume buttons
export let show_qr_manual_text_entry_option: boolean = false;
export let show_qr_manual_badge_id_entry_option: boolean = false;
export let show_qr_scan_result: boolean = true;
export let qr_fps = 10;
export let qr_viewfinder_width = 275; // 275 seems good... Need to not let the this be larger than the container which changes based on the width of the screen/window.
export let qr_facing_mode = 'environment'; // environment, user, { exact: 'environment'}, { exact: 'user'}
// *** Set initial variables
let scanning_status: string = 'not_started';
let qr_scan_result: null|string = null;
let qr_found_text: null|string = null;
let qr_entered_text: null|string = null;
let qr_entered_badge_id: null|string = null;
let show_qr_manual_entry: null|boolean = null;
let disable_submit_badge_id_btn: boolean = true;
let user_media_status = 'not_requested';
let debug_comment: string = 'Debugging QR Scanner';
let debug_info: any;
// let max_results: number = 50;
const dispatch = createEventDispatcher();
let html5_qr_code: any|null|string = null;
// let html5_qr_code = new Html5Qrcode(
// 'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
// );
// let qr_scan_cfg = { fps: 10, qrbox: 400 }; // default was 250 and using 300 when 600px
let qr_scan_cfg = { fps: qr_fps, qrbox: qr_viewfinder_width }; // 275 seems good... Need to not let the this be larger than the container which changes based on the width of the screen/window.
// let mounted = false;
onMount(() => {
console.log('** Element Mounted: ** QR Scanner');
// Wait 250ms for everything to fully load
// setTimeout(() => {
// console.log('** Element Mounted: ** QR Scanner - setTimeout');
// NOTE: We only want to trigger the scanning to start after the page has fully loaded.
navigator.mediaDevices.getUserMedia({video: true})
.then(successCallback, errorCallback);
console.log('** Element Mounted: ** QR Scanner - getUserMedia in setTimeout');
// mounted = true;
// }, 750);
// console.log('** Element Mounted: ** QR Scanner - setTimeout end');
// NOTE: This can only be done after the page has fully loaded.
// if (start_qr_scanner) {
// handle_start_qr_scanning();
// }
});
onDestroy(async () => {
console.log('** Element Destroyed: ** QR Scanner');
qr_scan_result = null;
qr_found_text = null;
await handle_stop_qr_scanning();
});
var successCallback = function(error: any) {
console.log('Camera access allowed');
user_media_status = 'allowed';
debug_comment = 'Camera Access Allowed';
debug_info = JSON.stringify(error);
if (html5_qr_code) {
console.log('html5_qr_code object found. Clearing and creating new Html5Qrcode...');
debug_info = 'html5_qr_code object found. Clearing and creating new Html5Qrcode...';
html5_qr_code.clear();
// document.getElementById('qr_scanner_viewfinder').classList.remove('d_none');
} else {
console.log('html5_qr_code not found. Creating new Html5Qrcode...');
debug_info = 'html5_qr_code not found. Creating new Html5Qrcode...';
}
html5_qr_code = new Html5Qrcode(
'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
);
debug_info = 'new Html5Qrcode for element id=qr_scanner_viewfinder';
if (start_qr_scanner) {
console.log('Ready to start QR scanning!');
debug_info = 'Ready to start QR scanning!';
handle_start_qr_scanning();
}
// let subject = 'Camera Access Allowed';
// let message = error;
// send_init_confirm_email(subject, message);
console.log('Dispatching qr_camera');
debug_info = 'Dispatching qr_camera';
dispatch('qr_camera', {
status: 'allowed',
});
// NOTE: This can only be done after the page has fully loaded.
// if (start_qr_scanner) {
// handle_start_qr_scanning();
// }
};
var errorCallback = function(error: any) {
if (error.name == 'NotAllowedError') {
console.log('Camera access not allowed!');
user_media_status = 'denied';
debug_comment = 'Camera Access Denied';
debug_info = JSON.stringify(error);
// alert('Error trying to start camera');
// alert(error);
let subject = 'Camera Access Denied';
let message = error;
send_init_confirm_email(subject, message);
dispatch('qr_camera', {
status: 'denied',
});
}
};
// $: if (start_qr_scanner && user_media_status == 'allowed' && (scanning_status == 'not_started' || scanning_status == 'paused')) {
// console.log('START QR SCANNING');
// handle_start_qr_scanning();
// } else {
// // console.log('STOP QR SCANNING');
// // handle_stop_qr_scanning();
// }
// $: if (mounted && start_qr_scanner) {
// console.log('START QR SCANNING');
// handle_start_qr_scanning();
// } else if (mounted && !start_qr_scanner) {
// console.log('STOP QR SCANNING');
// handle_stop_qr_scanning();
// }
async function handle_start_qr_scanning() {
console.log('*** handle_start_qr_scanning() ***');
if (user_media_status == 'denied') {
console.log('Camera access not allowed!');
return;
} else if (user_media_status == 'not_requested') {
console.log('Camera access not requested yet!');
return;
} else if (user_media_status == 'allowed') {
console.log('Camera access allowed!');
debug_info = 'Camera access allowed!';
} else {
console.log('Camera access status unknown! This should not happen?');
debug_info = 'Camera access status unknown! This should not happen?';
return;
}
qr_scan_result = null;
qr_found_text = null;
debug_comment = 'Starting QR Scanning...';
// if (html5_qr_code) {
// console.log('html5_qr_code object found. Clearing and creating new Html5Qrcode...');
// debug_info = 'html5_qr_code object found. Clearing and creating new Html5Qrcode...';
// html5_qr_code.clear();
// // document.getElementById('qr_scanner_viewfinder').classList.remove('d_none');
// html5_qr_code = new Html5Qrcode(
// 'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
// );
// } else {
// console.log('html5_qr_code not found. Creating new Html5Qrcode...');
// debug_info = 'html5_qr_code not found. Creating new Html5Qrcode...';
// html5_qr_code = new Html5Qrcode(
// 'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
// );
// }
debug_info = 'Check the state and start if not started...';
let current_state = await html5_qr_code.getState()
if (current_state == Html5QrcodeScannerState.NOT_STARTED) {
// console.log('Scanner is not started');
return await html5_qr_code.start({ facingMode: qr_facing_mode }, qr_scan_cfg, handle_qr_scan_success, handle_qr_scan_error)
.then((ignore: any) => {
console.log('Scanning has started');
scanning_status = 'scanning';
debug_info = 'Scanning has started';
// let subject = 'QR Scanning Started';
// let message = ignore;
// send_init_confirm_email(subject, message);
return true;
}).catch((err) => {
console.log('There was an error while trying to start the QR scanner');
scanning_status = 'start_error';
debug_info = 'Error starting scanner: ' + JSON.stringify(err);
// let subject = 'QR Scanning Start Error';
// let message = err;
// send_init_confirm_email(subject, message);
// Error getting userMedia, error = NotReadableError: Could not start video source
return false;
});
} else {
console.log('Scanner is already started');
debug_info = 'Scanner is already started';
return;
}
}
function handle_pause_qr_scanning() {
if (html5_qr_code && html5_qr_code.getState() != Html5QrcodeScannerState.SCANNING) {
console.log('Scanner is not scanning!');
return;
}
html5_qr_code.pause();
scanning_status = 'paused';
}
function handle_resume_qr_scanning() {
if (html5_qr_code && html5_qr_code.getState() != Html5QrcodeScannerState.PAUSED) {
console.log('Scanner is not paused!');
return;
}
document.getElementById('qr_scanner_viewfinder').classList.remove('d_none');
html5_qr_code.resume();
scanning_status = 'scanning';
}
async function handle_stop_qr_scanning() {
start_qr_scanner = false;
if (!html5_qr_code) {
console.log('html5_qr_code object found. Nothing to stop?');
return false;
}
let state = html5_qr_code.getState();
console.log('html5_qr_code state:', state);
if (state == Html5QrcodeScannerState.NOT_STARTED) {
console.log('Scanner is not started');
return;
}
if (state == Html5QrcodeScannerState.PAUSED || state == Html5QrcodeScannerState.SCANNING) {
console.log('Scanner is not started');
await html5_qr_code.stop()
scanning_status = 'not_started';
return;
}
await html5_qr_code.clear();
return true;
// html5_qr_code.pause();
// return html5_qr_code.stop()
// .then((ignore) => {
// console.log('Scanning has stopped');
// // document.getElementById('qr_scanner_viewfinder').classList.add('d_none');
// scanning_status = 'not_started';
// }).then((ignore) => {
// // html5_qr_code = null;
// // html5_qr_code.clear();
// }).catch((err) => {
// console.log('There was an error while trying to stop the scanning');
// return false;
// });
// html5_qr_code = null;
}
// Callback function for QrcodeSuccessCallback (decodedText: string, result: Html5QrcodeResult)
function handle_qr_scan_success(decoded_text, decoded_result) {
console.log('*** handle_qr_scan_success() ***');
console.log(`QR scanned = ${decoded_text}`, decoded_result);
qr_scan_result = decoded_text; // NOTE: decoded_result is not currently used by html5-qrcode
qr_found_text = decoded_text;
dispatch('qr_scan_result', {
result: qr_scan_result, // This text will need to be parsed to get more info.
text: qr_found_text, // This text will need to be parsed to get more info.
entry_method: 'QR',
});
// handle_pause_qr_scanning();
handle_stop_qr_scanning();
}
// Callback function for QrcodeErrorCallback (errorMessage: string, error: Html5QrcodeError)
// NOTE: Most of the time this is normal and not an actual error. It just did not find something to scan.
function handle_qr_scan_error(qr_error_message, qr_code_error) {
// console.log('*** handle_qr_scan_error() ***');
if (qr_code_error.type) {
console.log(`Error scanning code = ${qr_error_message}`, qr_code_error);
return;
}
}
$: if ( qr_entered_badge_id && qr_entered_badge_id.length >= 11 && qr_entered_badge_id && qr_entered_badge_id.length <= 14) {
disable_submit_badge_id_btn = false;
} else {
disable_submit_badge_id_btn = true;
}
function handle_qr_manual_entry() {
console.log('*** handle_qr_manual_entry() ***');
if (qr_entered_text) {
console.log(`QR entered text = ${qr_entered_text}`);
} else if (qr_entered_badge_id) {
console.log(`QR entered badge ID = ${qr_entered_badge_id}`);
qr_entered_text = `OBJ:ot:event_badge,oi:${qr_entered_badge_id}`;
console.log(`Parse to proper QR badge ID = ${qr_entered_text}`);
}
// html5_qr_code.stop().then((ignore) => {
// console.log('Scanning has stopped');
// document.getElementById('qr_scanner_viewfinder').classList.add('d_none');
// }).catch((err) => {
// console.log('There was an error while trying to stop the scanning');
// });
qr_scan_result = qr_entered_text;
dispatch('qr_scan_result', {
result: qr_scan_result,
entry_method: 'manual',
});
qr_scan_result = null;
qr_entered_text = null;
}
function send_init_confirm_email(subject, message) {
console.log(`*** send_init_confirm_email() *** ${subject}`);
let to_email = 'scott.idem+skdev@oneskyit.com';
// let origin_url = encodeURI(`${data.url.origin}`);
let full_subject = `${subject} Aether QR Scanner Debugging`;
let body_html = `
<div>Scott,
<p>This is an automatic debug email from the Aether QR scanner.</p>
</div>
<br>
<div>
Message:<br>
<pre>
${JSON.stringify(message)}
</pre>
</div>
`;
api.send_email({
api_cfg: $ae_api,
from_email: 'noreply+ae_qr_debug@oneskyit.com',
from_name: 'AE QR Debug',
to_email: to_email,
subject: full_subject,
body_html: body_html,
});
}
</script>
<section
class="ae_element qr_scanner border-2 border-slate-500/10 space-y-2 flex flex-col gap-1 justify-center items-center min-w-full max-w-full"
class:not_started={scanning_status == 'not_started'}
class:paused={scanning_status == 'paused'}
class:scanning={scanning_status == 'scanning'}
>
<!-- <header>
<h2>QR Scanner</h2>
</header> -->
<!-- <fieldset class=""> -->
<!-- <legend class="d_none">QR Scanner:</legend> -->
<div
class="ae_container qr_scanning_container"
>
<div
class="ae_options flex flex-row justify-center items-center gap-1 m-1"
>
{#if scanning_status == 'not_started' }
<button on:click={handle_start_qr_scanning} class="btn btn-lg variant-soft-primary btn_start"><span class="fas fa-qrcode mx-1"></span> Start Scanning</button>
<span class="loading-text">
Scanning stopped
</span>
{:else if scanning_status == 'paused' && show_pause_btn}
<button on:click={handle_resume_qr_scanning} class="btn btn-md variant-soft-primary btn_resume"><span class="fas fa-play"></span> Resume</button>
<span>Scanning paused</span>
{:else if scanning_status == 'scanning'}
<button on:click={handle_stop_qr_scanning} class="btn btn-md variant-soft-secondary btn_stop">
<span class="fas fa-crosshairs fa-spin opacity-50 m-1"></span>
<!-- <span class="fas fa-stop-circle m-1"></span> -->
Stop
</button>
{#if show_pause_btn}
<button on:click={handle_pause_qr_scanning} class="btn btn-lg variant-soft-secondary btn_pause"><span class="fas fa-pause-circle"></span> Pause</button>
{/if}
<!-- <span>Scanning for QR code...</span> -->
<!-- <div class="modal-loading"> -->
<!-- <span class="fas fa-crosshairs fa-spin opacity-50"></span> -->
<span class="loading-text">
Scanning for QR code...
</span>
<!-- </div> -->
{/if}
</div>
<div id="qr_scanner_viewfinder" class="qr_scanner_viewfinder grow flex flex-col justify-center items-center" style=""></div> <!-- width: 600px -->
</div>
{#if show_qr_manual_text_entry_option}
<div class="ae_container qr_manual_entry text_entry">
{#if show_qr_manual_entry}
<label for="entered_text" class="">Enter text</label>
<input type="text" name="entered_text" id="entered_text" bind:value="{qr_entered_text}">
<button on:click={handle_qr_manual_entry} class="btn btn-md variant-soft-warning"><span class="fas fa-paper-plane"></span> Submit Text</button>
<div class="search_by_text">
<input type='text' placeholder="Name or Email" label="Name or Email" value={search_query_str} focus={true} on:oninput={handle_oninput_search_query_str} />
</div>
{:else}
<button on:click={() => show_qr_manual_entry=true} class="btn btn-md variant-soft-warning"><span class="fas fa-keyboard"></span> Enter Text</button>
{/if}
</div>
{/if}
{#if show_qr_manual_badge_id_entry_option}
<div class="ae_container qr_manual_entry badge_id_entry">
{#if show_qr_manual_entry}
<form on:submit|preventDefault={() => handle_qr_manual_entry} class="flex">
<!-- <label for="entered_badge_id" class="">Enter badge ID</label>
<input type="text" name="entered_badge_id" id="entered_badge_id" bind:value="{qr_entered_badge_id}"> -->
<input
bind:value="{qr_entered_badge_id}"
type="text"
name="entered_badge_id"
id="entered_badge_id"
required
placeholder="Enter Badge ID"
class="input max-w-52"
/>
<button
type="submit"
on:click={handle_qr_manual_entry}
disabled={disable_submit_badge_id_btn}
class="btn btn-md variant-ghost-primary m-1"
class:btn_default={disable_submit_badge_id_btn}
class:btn_primary={!disable_submit_badge_id_btn}
>
<span class="fas fa-paper-plane mx-1"></span> Submit Badge ID
</button>
</form>
{:else}
<button on:click={() =>
{
handle_stop_qr_scanning();
show_qr_manual_entry=true;
}}
class="btn btn-md variant-soft-secondary m-1"
>
<span class="fas fa-keyboard mx-1"></span> Enter Badge ID
</button>
{/if}
</div>
{/if}
{#if show_qr_scan_result && qr_scan_result}
<div class="ae_container qr_scan_result">
<span class="label">Raw Result:</span>
<span id="qr_scan_result_value" class="value">{qr_scan_result}</span>
</div>
{/if}
<!-- {debug_comment ?? 'Debugging QR Scanner'}
{#if debug_info}
<div class="ae_container debug_info">
<span class="label">Debug Info:</span>
<span class="value">{debug_info}</span>
</div>
{/if} -->
<!-- </fieldset> -->
</section>
<style>
.not_started {
background-color: hsla(0, 100%, 75%, 0.3);
border-color: hsla(0, 100%, 75%, 0.6);
}
.paused {
background-color: hsla(60, 100%, 75%, 0.3);
border-color: hsla(60, 100%, 75%, 0.6);
}
.scanning {
background-color: hsla(120, 100%, 75%, 0.3);
border-color: hsla(120, 100%, 75%, 0.6);
}
.qr_scanner {
/* outline: solid thin pink; */
max-width: 100vw;
/* overflow-x: scroll; */
display: flex;
flex-direction: column;
/* flex-wrap: wrap; */
justify-content: flex-start;
align-items: center; /* center */
align-content: stretch;
}
.ae_element.qr_scanner div.qr_scanner_viewfinder {
/* max-width: 100vw; */
/* contain: content; */
/* contain: contain; */
}
.qr_scanner .qr_scanner_viewfinder {
/* outline: dashed medium blue; */
min-width: 400px;
width: 100%;
/* max-width: 100%; */
max-width: 500px;
/* max-width: 100vw; */
/* outline: solid thin red; */
contain: contain;
overflow-x: scroll;
}
@media (max-width: 767px) {
.qr_scanner .qr_scanner_viewfinder {
/* outline: dashed medium red; */
min-width: 80vw;
/* width: 100%; */
/* max-width: 100%; */
/* max-width: 450px; */
max-width: 100vw;
margin: 0;
padding: 0;
}
}
</style>

View File

@@ -0,0 +1,670 @@
<script lang="ts">
// *** Import Svelte core
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
// import 'html5-qrcode';
import {Html5Qrcode, Html5QrcodeScannerState, Html5QrcodeSupportedFormats} from 'html5-qrcode';
// *** Import Aether core variables and functions
import { api } from '$lib/api';
import { ae_api } from '$lib/ae_stores';
// *** Import Aether core components
// import Element_input from './element_input.svelte';
// import ae from '/element_input.svelte';
// import Input_element from '/element_input.svelte';
// *** Import Aether module variables and functions
// *** Import Aether module components
// *** Export/Exposed variables and functions for component
export let start_qr_scanner: boolean = true;
export let show_pause_btn: boolean = false; // pause and resume buttons
export let show_qr_manual_text_entry_option: boolean = false;
export let show_qr_manual_badge_id_entry_option: boolean = false;
export let show_qr_scan_result: boolean = true;
export let qr_fps = 10;
export let qr_viewfinder_width = 275; // 275 seems good... Need to not let the this be larger than the container which changes based on the width of the screen/window.
export let qr_facing_mode = 'environment'; // environment, user, { exact: 'environment'}, { exact: 'user'}
// *** Set initial variables
let scanning_status: string = 'not_started';
let qr_scan_result: null|string = null;
let qr_found_text: null|string = null;
let qr_entered_text: null|string = null;
let qr_entered_badge_id: null|string = null;
let show_qr_manual_entry: null|boolean = null;
let disable_submit_badge_id_btn: boolean = true;
let user_media_status = 'not_requested';
let debug_comment: string = 'Debugging QR Scanner';
let debug_info: any;
let html5_qr_code: any|null|string = null;
// let qr_scan_cfg = { fps: 10, qrbox: 400 }; // default was 250 and using 300 when 600px
let qr_scan_cfg = { fps: qr_fps, qrbox: qr_viewfinder_width }; // 275 seems good... Need to not let the this be larger than the container which changes based on the width of the screen/window.
// const html5QrCode = new Html5Qrcode(
// 'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
// );
onMount(() => {
console.log('** Element Mounted: ** QR Scanner');
// html5_qr_code = new Html5Qrcode(
// 'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
// );
// navigator.mediaDevices.getUserMedia({video: true})
// .then(get_user_media_success, get_user_media_error);
// console.log('** Element Mounted: ** QR Scanner - getUserMedia in setTimeout');
});
onDestroy(async () => {
console.log('** Element Destroyed: ** QR Scanner');
qr_scan_result = null;
qr_found_text = null;
await handle_stop_qr_scanning();
});
var get_user_media_success = function(error: any) {
console.log('Camera access allowed');
user_media_status = 'allowed';
debug_comment = 'Camera Access Allowed';
debug_info = JSON.stringify(error);
if (html5_qr_code) {
console.log('html5_qr_code object found. Clearing and creating new Html5Qrcode...');
debug_info = 'html5_qr_code object found. Clearing and creating new Html5Qrcode...';
html5_qr_code.clear();
// document.getElementById('qr_scanner_viewfinder').classList.remove('d_none');
} else {
console.log('html5_qr_code not found. Creating new Html5Qrcode...');
debug_info = 'html5_qr_code not found. Creating new Html5Qrcode...';
html5_qr_code = new Html5Qrcode(
'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
);
}
// html5_qr_code = new Html5Qrcode(
// 'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
// );
debug_info = 'new Html5Qrcode for element id=qr_scanner_viewfinder';
if (start_qr_scanner && 1==2) {
console.log('Ready to start QR scanning! (after x500ms)');
debug_comment = 'Starting QR after 500ms...';
debug_info = 'Ready to start QR scanning! (after 2500ms)';
setTimeout(() => {
console.log('Inside QR scanning timeout after x500ms...');
// handle_start_qr_scanning();
handle_start_qr_scanning_trust();
}, 2500);
console.log('Started QR scanning after x500ms...');
}
// let subject = 'Camera Access Allowed';
// let message = error;
// send_init_confirm_email(subject, message);
// console.log('Dispatching qr_camera');
// debug_info = 'Dispatching qr_camera';
// dispatch('qr_camera', {
// status: 'allowed',
// });
// NOTE: This can only be done after the page has fully loaded.
// if (start_qr_scanner) {
// handle_start_qr_scanning();
// }
};
var get_user_media_error = function(error: any) {
if (error.name == 'NotAllowedError') {
console.log('Camera access not allowed!');
user_media_status = 'denied';
debug_comment = 'Camera Access Denied';
debug_info = JSON.stringify(error);
// alert('Error trying to start camera');
// alert(error);
let subject = 'Camera Access Denied';
let message = error;
send_init_confirm_email(subject, message);
// dispatch('qr_camera', {
// status: 'denied',
// });
}
};
// $: if (start_qr_scanner && user_media_status == 'allowed' && (scanning_status == 'not_started' || scanning_status == 'paused')) {
// console.log('START QR SCANNING');
// handle_start_qr_scanning();
// } else {
// // console.log('STOP QR SCANNING');
// // handle_stop_qr_scanning();
// }
// $: if (mounted && start_qr_scanner) {
// console.log('START QR SCANNING');
// handle_start_qr_scanning();
// } else if (mounted && !start_qr_scanner) {
// console.log('STOP QR SCANNING');
// handle_stop_qr_scanning();
// }
async function handle_start_qr_scanning_trust() {
console.log('*** handle_start_qr_scanning_trust() ***');
qr_scan_result = null;
qr_found_text = null;
debug_comment = 'Starting trusting QR scanning...';
debug_info = 'Just start!';
await html5_qr_code.clear();
html5_qr_code.start({ facingMode: qr_facing_mode }, qr_scan_cfg, handle_qr_scan_success, handle_qr_scan_error)
.then((ignore: any) => {
console.log('Scanning has started');
scanning_status = 'scanning';
debug_info = 'Scanning has started';
// let subject = 'QR Scanning Started';
// let message = ignore;
// send_init_confirm_email(subject, message);
return true;
}).catch((err) => {
console.log('There was an error while trying to start the QR scanner');
scanning_status = 'start_error';
debug_info = 'Error starting scanner: ' + JSON.stringify(err);
// let subject = 'QR Scanning Start Error';
// let message = err;
// send_init_confirm_email(subject, message);
// Error getting userMedia, error = NotReadableError: Could not start video source
return false;
});
return true;
}
async function handle_start_qr_scanning() {
console.log('*** handle_start_qr_scanning() ***');
if (user_media_status == 'denied') {
console.log('Camera access not allowed!');
return;
} else if (user_media_status == 'not_requested') {
console.log('Camera access not requested yet!');
return;
} else if (user_media_status == 'allowed') {
console.log('Camera access allowed!');
debug_info = 'Camera access allowed!';
} else {
console.log('Camera access status unknown! This should not happen?');
debug_info = 'Camera access status unknown! This should not happen?';
return;
}
qr_scan_result = null;
qr_found_text = null;
debug_comment = 'Starting QR Scanning...';
debug_info = 'Check the state and start if not started...';
let current_state = await html5_qr_code.getState()
if (current_state == Html5QrcodeScannerState.NOT_STARTED) {
// console.log('Scanner is not started');
return await html5_qr_code.start({ facingMode: qr_facing_mode }, qr_scan_cfg, handle_qr_scan_success, handle_qr_scan_error)
.then((ignore: any) => {
console.log('Scanning has started');
scanning_status = 'scanning';
debug_info = 'Scanning has started';
// let subject = 'QR Scanning Started';
// let message = ignore;
// send_init_confirm_email(subject, message);
return true;
}).catch((err) => {
console.log('There was an error while trying to start the QR scanner');
scanning_status = 'start_error';
debug_info = 'Error starting scanner: ' + JSON.stringify(err);
// let subject = 'QR Scanning Start Error';
// let message = err;
// send_init_confirm_email(subject, message);
// Error getting userMedia, error = NotReadableError: Could not start video source
return false;
});
} else {
console.log('Scanner is already started');
debug_info = 'Scanner is already started';
return;
}
}
function handle_pause_qr_scanning() {
if (html5_qr_code && html5_qr_code.getState() != Html5QrcodeScannerState.SCANNING) {
console.log('Scanner is not scanning!');
return;
}
html5_qr_code.pause();
scanning_status = 'paused';
}
function handle_resume_qr_scanning() {
if (html5_qr_code && html5_qr_code.getState() != Html5QrcodeScannerState.PAUSED) {
console.log('Scanner is not paused!');
return;
}
html5_qr_code.resume();
scanning_status = 'scanning';
}
async function handle_stop_qr_scanning() {
start_qr_scanner = false;
if (!html5_qr_code) {
console.log('html5_qr_code object found. Nothing to stop?');
return false;
}
await html5_qr_code.stop();
// let state = html5_qr_code.getState();
// console.log('html5_qr_code state:', state);
// if (state == Html5QrcodeScannerState.NOT_STARTED) {
// console.log('Scanner is not started');
// return;
// }
// if (state == Html5QrcodeScannerState.PAUSED || state == Html5QrcodeScannerState.SCANNING) {
// console.log('Scanner is not started');
// await html5_qr_code.stop();
// scanning_status = 'not_started';
// return;
// }
await html5_qr_code.clear();
return true;
// html5_qr_code.pause();
// return html5_qr_code.stop()
// .then((ignore) => {
// console.log('Scanning has stopped');
// // document.getElementById('qr_scanner_viewfinder').classList.add('d_none');
// scanning_status = 'not_started';
// }).then((ignore) => {
// // html5_qr_code = null;
// // html5_qr_code.clear();
// }).catch((err) => {
// console.log('There was an error while trying to stop the scanning');
// return false;
// });
// html5_qr_code = null;
}
// Callback function for QrcodeSuccessCallback (decodedText: string, result: Html5QrcodeResult)
function handle_qr_scan_success(decoded_text, decoded_result) {
console.log('*** handle_qr_scan_success() ***');
console.log(`QR scanned = ${decoded_text}`, decoded_result);
qr_scan_result = decoded_text; // NOTE: decoded_result is not currently used by html5-qrcode
qr_found_text = decoded_text;
dispatch('qr_scan_result', {
result: qr_scan_result, // This text will need to be parsed to get more info.
text: qr_found_text, // This text will need to be parsed to get more info.
entry_method: 'QR',
});
// handle_pause_qr_scanning();
handle_stop_qr_scanning();
}
// Callback function for QrcodeErrorCallback (errorMessage: string, error: Html5QrcodeError)
// NOTE: Most of the time this is normal and not an actual error. It just did not find something to scan.
function handle_qr_scan_error(qr_error_message, qr_code_error) {
// console.log('*** handle_qr_scan_error() ***');
if (qr_code_error.type) {
console.log(`Error scanning code = ${qr_error_message}`, qr_code_error);
return;
}
}
$: if ( qr_entered_badge_id && qr_entered_badge_id.length >= 11 && qr_entered_badge_id && qr_entered_badge_id.length <= 14) {
disable_submit_badge_id_btn = false;
} else {
disable_submit_badge_id_btn = true;
}
function handle_qr_manual_entry() {
console.log('*** handle_qr_manual_entry() ***');
if (qr_entered_text) {
console.log(`QR entered text = ${qr_entered_text}`);
} else if (qr_entered_badge_id) {
console.log(`QR entered badge ID = ${qr_entered_badge_id}`);
qr_entered_text = `OBJ:ot:event_badge,oi:${qr_entered_badge_id}`;
console.log(`Parse to proper QR badge ID = ${qr_entered_text}`);
}
// html5_qr_code.stop().then((ignore) => {
// console.log('Scanning has stopped');
// document.getElementById('qr_scanner_viewfinder').classList.add('d_none');
// }).catch((err) => {
// console.log('There was an error while trying to stop the scanning');
// });
qr_scan_result = qr_entered_text;
dispatch('qr_scan_result', {
result: qr_scan_result,
entry_method: 'manual',
});
qr_scan_result = null;
qr_entered_text = null;
}
function send_init_confirm_email(subject, message) {
console.log(`*** send_init_confirm_email() *** ${subject}`);
let to_email = 'scott.idem+skdev@oneskyit.com';
// let origin_url = encodeURI(`${data.url.origin}`);
let full_subject = `${subject} Aether QR Scanner Debugging`;
let body_html = `
<div>Scott,
<p>This is an automatic debug email from the Aether QR scanner.</p>
</div>
<br>
<div>
Message:<br>
<pre>
${JSON.stringify(message)}
</pre>
</div>
`;
api.send_email({
api_cfg: $ae_api,
from_email: 'noreply+ae_qr_debug@oneskyit.com',
from_name: 'AE QR Debug',
to_email: to_email,
subject: full_subject,
body_html: body_html,
});
}
</script>
<section
class="ae_element qr_scanner border-2 border-slate-500/10 space-y-2 flex flex-col gap-1 justify-center items-center min-w-full max-w-full"
class:not_started={scanning_status == 'not_started'}
class:paused={scanning_status == 'paused'}
class:scanning={scanning_status == 'scanning'}
>
<!-- <header>
<h2>QR Scanner</h2>
</header> -->
<!-- <fieldset class=""> -->
<!-- <legend class="d_none">QR Scanner:</legend> -->
<div
class="ae_container qr_scanning_container"
>
<div
class="ae_options flex flex-row gap-1 m-1"
>
<button
type="button"
on:click={ () => {
navigator.mediaDevices.getUserMedia({video: true})
.then(get_user_media_success, get_user_media_error);
}}
class="ae_btn__allow_camera btn btn-sm variant-soft-primary"
>
<span class="fas fa-camera mx-1"></span>
Allow Camera Access
</button>
<button
type="button"
on:click={ () => {
handle_start_qr_scanning_trust();
// Select back camera or fail with `OverconstrainedError`.
// html5_qr_code.start({ facingMode: { exact: "environment"} }, config, qrCodeSuccessCallback);
}}
class="ae_btn__start btn btn-sm variant-soft-primary"
>
<span class="fas fa-qrcode mx-1"></span>
Start Scanning
</button>
<button
on:click={ () => {
// Select back camera or fail with `OverconstrainedError`.
html5_qr_code.start({ facingMode: { exact: "environment"} }, config, qrCodeSuccessCallback);
}}
class="ae_btn__resume btn btn-sm variant-soft-primary">
<span class="fas fa-play"></span>
Resume
</button>
<button
on:click={handle_stop_qr_scanning}
class="ae_btn__stop btn btn-sm variant-soft-secondary"
>
<span class="fas fa-crosshairs fa-spin opacity-50 m-1"></span>
<!-- <span class="fas fa-stop-circle m-1"></span> -->
Stop
</button>
</div>
<div id="qr_scanner_viewfinder" class="qr_scanner_viewfinder grow flex flex-col justify-center items-center" style=""></div> <!-- width: 600px -->
</div>
{#if show_qr_manual_text_entry_option}
<div class="ae_container qr_manual_entry text_entry">
{#if show_qr_manual_entry}
<label for="entered_text" class="">Enter text</label>
<input type="text" name="entered_text" id="entered_text" bind:value="{qr_entered_text}">
<button on:click={handle_qr_manual_entry} class="btn btn-md variant-soft-warning"><span class="fas fa-paper-plane"></span> Submit Text</button>
<div class="search_by_text">
<input type='text' placeholder="Name or Email" label="Name or Email" value={search_query_str} focus={true} on:oninput={handle_oninput_search_query_str} />
</div>
{:else}
<button on:click={() => show_qr_manual_entry=true} class="btn btn-md variant-soft-warning"><span class="fas fa-keyboard"></span> Enter Text</button>
{/if}
</div>
{/if}
{#if show_qr_manual_badge_id_entry_option}
<div class="ae_container qr_manual_entry badge_id_entry">
{#if show_qr_manual_entry}
<form on:submit|preventDefault={() => handle_qr_manual_entry} class="flex">
<!-- <label for="entered_badge_id" class="">Enter badge ID</label>
<input type="text" name="entered_badge_id" id="entered_badge_id" bind:value="{qr_entered_badge_id}"> -->
<input
bind:value="{qr_entered_badge_id}"
type="text"
name="entered_badge_id"
id="entered_badge_id"
required
placeholder="Enter Badge ID"
class="input max-w-52"
/>
<button
type="submit"
on:click={handle_qr_manual_entry}
disabled={disable_submit_badge_id_btn}
class="btn btn-md variant-ghost-primary m-1"
class:btn_default={disable_submit_badge_id_btn}
class:btn_primary={!disable_submit_badge_id_btn}
>
<span class="fas fa-paper-plane mx-1"></span> Submit Badge ID
</button>
</form>
{:else}
<button on:click={() => show_qr_manual_entry=true} class="btn btn-md variant-soft-secondary m-1"><span class="fas fa-keyboard mx-1"></span> Enter Badge ID</button>
{/if}
</div>
{/if}
{#if show_qr_scan_result && qr_scan_result}
<div class="ae_container qr_scan_result">
<span class="label">Raw Result:</span>
<span id="qr_scan_result_value" class="value">{qr_scan_result}</span>
</div>
{/if}
{debug_comment ?? 'Debugging QR Scanner'}
{#if debug_info}
<div class="ae_container debug_info">
<span class="label">Debug Info:</span>
<span class="value">{debug_info}</span>
</div>
{/if}
<!-- </fieldset> -->
</section>
<style>
.not_started {
background-color: hsla(0, 100%, 75%, 0.3);
border-color: hsla(0, 100%, 75%, 0.6);
}
.paused {
background-color: hsla(60, 100%, 75%, 0.3);
border-color: hsla(60, 100%, 75%, 0.6);
}
.scanning {
background-color: hsla(120, 100%, 75%, 0.3);
border-color: hsla(120, 100%, 75%, 0.6);
}
.qr_scanner {
/* outline: solid thin pink; */
max-width: 100vw;
/* overflow-x: scroll; */
display: flex;
flex-direction: column;
/* flex-wrap: wrap; */
justify-content: flex-start;
align-items: center; /* center */
align-content: stretch;
}
.ae_element.qr_scanner div.qr_scanner_viewfinder {
/* max-width: 100vw; */
/* contain: content; */
/* contain: contain; */
}
.qr_scanner .qr_scanner_viewfinder {
/* outline: dashed medium blue; */
min-width: 400px;
width: 100%;
/* max-width: 100%; */
max-width: 500px;
/* max-width: 100vw; */
/* outline: solid thin red; */
contain: contain;
overflow-x: scroll;
}
@media (max-width: 767px) {
.qr_scanner .qr_scanner_viewfinder {
/* outline: dashed medium red; */
min-width: 80vw;
/* width: 100%; */
/* max-width: 100%; */
/* max-width: 450px; */
max-width: 100vw;
margin: 0;
padding: 0;
}
}
</style>

View File

@@ -0,0 +1,560 @@
<script lang="ts">
// *** Import Svelte core
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
// import 'html5-qrcode';
import {Html5Qrcode, Html5QrcodeScannerState, Html5QrcodeSupportedFormats} from 'html5-qrcode';
// *** Import Aether core variables and functions
import { api } from '$lib/api';
import { ae_api } from '$lib/ae_stores';
// *** Import Aether core components
// import Element_input from './element_input.svelte';
// import ae from '/element_input.svelte';
// import Input_element from '/element_input.svelte';
// *** Import Aether module variables and functions
// *** Import Aether module components
// *** Export/Exposed variables and functions for component
export let start_qr_scanner: boolean = true;
export let show_pause_btn: boolean = false; // pause and resume buttons
export let show_qr_manual_text_entry_option: boolean = false;
export let show_qr_manual_badge_id_entry_option: boolean = false;
export let show_qr_scan_result: boolean = true;
export let qr_fps = 10;
export let qr_viewfinder_width = 275; // 275 seems good... Need to not let the this be larger than the container which changes based on the width of the screen/window.
export let qr_facing_mode = 'environment'; // environment, user, { exact: 'environment'}, { exact: 'user'}
const dispatch = createEventDispatcher();
// *** Set initial variables
let scanning_status: string = 'not_started';
let qr_scan_result: null|string = null;
let qr_found_text: null|string = null;
let qr_entered_text: null|string = null;
let qr_entered_badge_id: null|string = null;
let show_qr_manual_entry: null|boolean = null;
let disable_submit_badge_id_btn: boolean = true;
let user_media_status = 'not_requested';
let debug_comment: string = 'Debugging QR Scanner';
let debug_info: any;
let html5_qr_code: any|null|string = null;
// let qr_scan_cfg = { fps: 10, qrbox: 400 }; // default was 250 and using 300 when 600px
let qr_scan_cfg = { fps: qr_fps, qrbox: qr_viewfinder_width }; // 275 seems good... Need to not let the this be larger than the container which changes based on the width of the screen/window.
// const html5QrCode = new Html5Qrcode(
// 'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
// );
onMount(() => {
console.log('** Element Mounted: ** QR Scanner');
// html5_qr_code = new Html5Qrcode(
// 'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
// );
// navigator.mediaDevices.getUserMedia({video: true})
// .then(get_user_media_success, get_user_media_error);
// console.log('** Element Mounted: ** QR Scanner - getUserMedia in setTimeout');
});
onDestroy(async () => {
console.log('** Element Destroyed: ** QR Scanner');
qr_scan_result = null;
qr_found_text = null;
await handle_stop_qr_scanning();
});
var get_user_media_success = function(error: any) {
console.log('Camera access allowed');
user_media_status = 'allowed';
debug_comment = 'Camera Access Allowed';
debug_info = JSON.stringify(error);
if (html5_qr_code) {
console.log('html5_qr_code object found. Clearing and creating new Html5Qrcode...');
debug_info = 'html5_qr_code object found. Clearing and creating new Html5Qrcode...';
html5_qr_code.clear();
// document.getElementById('qr_scanner_viewfinder').classList.remove('d_none');
} else {
console.log('html5_qr_code not found. Creating new Html5Qrcode...');
debug_info = 'html5_qr_code not found. Creating new Html5Qrcode...';
html5_qr_code = new Html5Qrcode(
'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
);
}
// html5_qr_code = new Html5Qrcode(
// 'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
// );
debug_info = 'new Html5Qrcode for element id=qr_scanner_viewfinder';
if (start_qr_scanner && 1==2) {
console.log('Ready to start QR scanning! (after x500ms)');
debug_comment = 'Starting QR after 500ms...';
debug_info = 'Ready to start QR scanning! (after 2500ms)';
setTimeout(() => {
console.log('Inside QR scanning timeout after x500ms...');
handle_start_qr_scanning_trust();
}, 2500);
console.log('Started QR scanning after x500ms...');
}
// let subject = 'Camera Access Allowed';
// let message = error;
// send_init_confirm_email(subject, message);
console.log('Dispatching qr_camera');
debug_info = 'Dispatching qr_camera';
dispatch('qr_camera', {
status: 'allowed',
});
};
var get_user_media_error = function(error: any) {
if (error.name == 'NotAllowedError') {
console.log('Camera access not allowed!');
user_media_status = 'denied';
debug_comment = 'Camera Access Denied';
debug_info = JSON.stringify(error);
// alert('Error trying to start camera');
// alert(error);
let subject = 'Camera Access Denied';
let message = error;
send_init_confirm_email(subject, message);
// dispatch('qr_camera', {
// status: 'denied',
// });
}
};
// $: if (start_qr_scanner && user_media_status == 'allowed' && (scanning_status == 'not_started' || scanning_status == 'paused')) {
// console.log('START QR SCANNING');
// handle_start_qr_scanning();
// } else {
// // console.log('STOP QR SCANNING');
// // handle_stop_qr_scanning();
// }
// $: if (mounted && start_qr_scanner) {
// console.log('START QR SCANNING');
// handle_start_qr_scanning();
// } else if (mounted && !start_qr_scanner) {
// console.log('STOP QR SCANNING');
// handle_stop_qr_scanning();
// }
async function handle_start_qr_scanning_trust() {
console.log('*** handle_start_qr_scanning_trust() ***');
qr_scan_result = null;
qr_found_text = null;
debug_comment = 'Starting trusting QR scanning...';
debug_info = 'Just start!';
await html5_qr_code.clear();
html5_qr_code.start({ facingMode: qr_facing_mode }, qr_scan_cfg, handle_qr_scan_success, handle_qr_scan_error)
.then((ignore: any) => {
console.log('Scanning has started');
scanning_status = 'scanning';
debug_info = 'Scanning has started';
// let subject = 'QR Scanning Started';
// let message = ignore;
// send_init_confirm_email(subject, message);
return true;
}).catch((err) => {
console.log('There was an error while trying to start the QR scanner');
scanning_status = 'start_error';
debug_info = 'Error starting scanner: ' + JSON.stringify(err);
// let subject = 'QR Scanning Start Error';
// let message = err;
// send_init_confirm_email(subject, message);
// Error getting userMedia, error = NotReadableError: Could not start video source
return false;
});
return true;
}
async function handle_stop_qr_scanning() {
start_qr_scanner = false;
if (!html5_qr_code) {
console.log('html5_qr_code object found. Nothing to stop?');
scanning_status = 'not_started';
return false;
}
await html5_qr_code.stop();
scanning_status = 'not_started';
await html5_qr_code.clear();
return true;
}
// Callback function for QrcodeSuccessCallback (decodedText: string, result: Html5QrcodeResult)
function handle_qr_scan_success(decoded_text, decoded_result) {
console.log(`*** handle_qr_scan_success() *** QR scanned = ${decoded_text}`, decoded_result);
qr_scan_result = decoded_text; // NOTE: decoded_result is not currently used by html5-qrcode
qr_found_text = decoded_text;
dispatch('qr_scan_result', {
result: qr_scan_result, // This text will need to be parsed to get more info.
text: qr_found_text, // This text will need to be parsed to get more info.
entry_method: 'QR',
});
// handle_pause_qr_scanning();
handle_stop_qr_scanning();
}
// Callback function for QrcodeErrorCallback (errorMessage: string, error: Html5QrcodeError)
// NOTE: Most of the time this is normal and not an actual error. It just did not find something to scan.
function handle_qr_scan_error(qr_error_message, qr_code_error) {
// console.log('*** handle_qr_scan_error() ***');
if (qr_code_error.type) {
console.log(`Error scanning code = ${qr_error_message}`, qr_code_error);
return;
}
}
$: if ( qr_entered_badge_id && qr_entered_badge_id.length >= 11 && qr_entered_badge_id && qr_entered_badge_id.length <= 14) {
disable_submit_badge_id_btn = false;
} else {
disable_submit_badge_id_btn = true;
}
function handle_qr_manual_entry() {
console.log('*** handle_qr_manual_entry() ***');
if (qr_entered_text) {
console.log(`QR entered text = ${qr_entered_text}`);
} else if (qr_entered_badge_id) {
console.log(`QR entered badge ID = ${qr_entered_badge_id}`);
qr_entered_text = `OBJ:ot:event_badge,oi:${qr_entered_badge_id}`;
console.log(`Parse to proper QR badge ID = ${qr_entered_text}`);
}
// html5_qr_code.stop().then((ignore) => {
// console.log('Scanning has stopped');
// document.getElementById('qr_scanner_viewfinder').classList.add('d_none');
// }).catch((err) => {
// console.log('There was an error while trying to stop the scanning');
// });
qr_scan_result = qr_entered_text;
dispatch('qr_scan_result', {
result: qr_scan_result,
entry_method: 'manual',
});
qr_scan_result = null;
qr_entered_text = null;
}
function send_init_confirm_email(subject, message) {
console.log(`*** send_init_confirm_email() *** ${subject}`);
let to_email = 'scott.idem+skdev@oneskyit.com';
// let origin_url = encodeURI(`${data.url.origin}`);
let full_subject = `${subject} Aether QR Scanner Debugging`;
let body_html = `
<div>Scott,
<p>This is an automatic debug email from the Aether QR scanner.</p>
</div>
<br>
<div>
Message:<br>
<pre>
${JSON.stringify(message)}
</pre>
</div>
`;
api.send_email({
api_cfg: $ae_api,
from_email: 'noreply+ae_qr_debug@oneskyit.com',
from_name: 'AE QR Debug',
to_email: to_email,
subject: full_subject,
body_html: body_html,
});
}
</script>
<section
class="ae_element qr_scanner border-2 border-slate-500/10 space-y-2 flex flex-col gap-1 justify-center items-center min-w-full max-w-full"
class:not_started={scanning_status == 'not_started'}
class:paused={scanning_status == 'paused'}
class:scanning={scanning_status == 'scanning'}
>
<!-- <header>
<h2>QR Scanner</h2>
</header> -->
<!-- <fieldset class=""> -->
<!-- <legend class="d_none">QR Scanner:</legend> -->
<div
class="ae_container qr_scanning_container"
>
<div
class="ae_options flex flex-row justify-center items-center gap-1 m-1"
>
<button
type="button"
on:click={ () => {
navigator.mediaDevices.getUserMedia({video: true})
.then(get_user_media_success, get_user_media_error);
}}
class="ae_btn__allow_camera btn btn-sm variant-soft-primary"
>
<span class="fas fa-camera mx-1"></span>
Allow Camera Access
</button>
<button
type="button"
on:click={ () => {
handle_start_qr_scanning_trust();
// Select back camera or fail with `OverconstrainedError`.
// html5_qr_code.start({ facingMode: { exact: "environment"} }, config, qrCodeSuccessCallback);
}}
class="ae_btn__start btn btn-sm variant-soft-primary"
>
<span class="fas fa-qrcode mx-1"></span>
Start Scanning
</button>
<!-- <button
on:click={ () => {
html5_qr_code.start({ facingMode: { exact: "environment"} }, config, qrCodeSuccessCallback);
}}
class="ae_btn__resume btn btn-sm variant-soft-primary">
<span class="fas fa-play"></span>
Resume
</button> -->
{#if (scanning_status == 'scanning')}
<button
on:click={handle_stop_qr_scanning}
class="ae_btn__stop btn btn-sm variant-soft-secondary"
>
<span class="fas fa-crosshairs fa-spin opacity-50 m-1"></span>
<!-- <span class="fas fa-stop-circle m-1"></span> -->
Stop
</button>
{/if}
</div>
<div id="qr_scanner_viewfinder" class="qr_scanner_viewfinder grow flex flex-col justify-center items-center" style=""></div> <!-- width: 600px -->
</div>
{#if show_qr_manual_text_entry_option}
<div class="ae_container qr_manual_entry text_entry">
{#if show_qr_manual_entry}
<label for="entered_text" class="">Enter text</label>
<input type="text" name="entered_text" id="entered_text" bind:value="{qr_entered_text}">
<button on:click={handle_qr_manual_entry} class="btn btn-md variant-soft-warning"><span class="fas fa-paper-plane"></span> Submit Text</button>
<div class="search_by_text">
<input type='text' placeholder="Name or Email" label="Name or Email" value={search_query_str} focus={true} on:oninput={handle_oninput_search_query_str} />
</div>
{:else}
<button on:click={() => {
handle_stop_qr_scanning();
show_qr_manual_entry=true;
}}
class="btn btn-md variant-soft-warning m-1"
>
<span class="fas fa-keyboard mx-1"></span> Enter Text
</button>
{/if}
</div>
{/if}
{#if show_qr_manual_badge_id_entry_option}
<div class="ae_container qr_manual_entry badge_id_entry">
{#if show_qr_manual_entry}
<form on:submit|preventDefault={() => handle_qr_manual_entry} class="flex">
<!-- <label for="entered_badge_id" class="">Enter badge ID</label>
<input type="text" name="entered_badge_id" id="entered_badge_id" bind:value="{qr_entered_badge_id}"> -->
<input
bind:value="{qr_entered_badge_id}"
type="text"
name="entered_badge_id"
id="entered_badge_id"
required
placeholder="Enter Badge ID"
class="input max-w-52"
/>
<button
type="submit"
on:click={handle_qr_manual_entry}
disabled={disable_submit_badge_id_btn}
class="btn btn-md variant-ghost-primary m-1"
class:btn_default={disable_submit_badge_id_btn}
class:btn_primary={!disable_submit_badge_id_btn}
>
<span class="fas fa-paper-plane mx-1"></span> Submit Badge ID
</button>
</form>
{:else}
<button on:click={() => {
handle_stop_qr_scanning();
show_qr_manual_entry=true;
}}
class="btn btn-md variant-soft-secondary m-1"
>
<span class="fas fa-keyboard mx-1"></span> Enter Badge ID
</button>
{/if}
</div>
{/if}
{#if show_qr_scan_result && qr_scan_result}
<div class="ae_container qr_scan_result">
<span class="label">Raw Result:</span>
<span id="qr_scan_result_value" class="value">{qr_scan_result}</span>
</div>
{/if}
<!-- {debug_comment ?? 'Debugging QR Scanner'}
{#if debug_info}
<div class="ae_container debug_info">
<span class="label">Debug Info:</span>
<span class="value">{debug_info}</span>
</div>
{/if} -->
<!-- </fieldset> -->
<p>v2 - Try pressing the "Allow Camera Access" button and then the "Start Scanning" button if it does not start on its own. This fix is not perfect. A permanent solution is actively being worked on in the development version.</p>
</section>
<style>
.not_started {
background-color: hsla(0, 100%, 75%, 0.3);
border-color: hsla(0, 100%, 75%, 0.6);
}
.paused {
background-color: hsla(60, 100%, 75%, 0.3);
border-color: hsla(60, 100%, 75%, 0.6);
}
.scanning {
background-color: hsla(120, 100%, 75%, 0.3);
border-color: hsla(120, 100%, 75%, 0.6);
}
.qr_scanner {
/* outline: solid thin pink; */
max-width: 100vw;
/* overflow-x: scroll; */
display: flex;
flex-direction: column;
/* flex-wrap: wrap; */
justify-content: flex-start;
align-items: center; /* center */
align-content: stretch;
}
.ae_element.qr_scanner div.qr_scanner_viewfinder {
/* max-width: 100vw; */
/* contain: content; */
/* contain: contain; */
}
.qr_scanner .qr_scanner_viewfinder {
/* outline: dashed medium blue; */
min-width: 400px;
width: 100%;
/* max-width: 100%; */
max-width: 500px;
/* max-width: 100vw; */
/* outline: solid thin red; */
contain: contain;
overflow-x: scroll;
}
@media (max-width: 767px) {
.qr_scanner .qr_scanner_viewfinder {
/* outline: dashed medium red; */
min-width: 80vw;
/* width: 100%; */
/* max-width: 100%; */
/* max-width: 450px; */
max-width: 100vw;
margin: 0;
padding: 0;
}
}
</style>

View File

@@ -0,0 +1,146 @@
<script lang="ts">
import { onMount } from 'svelte';
// *** Import Aether core variables and functions
import type { key_val } from '$lib/ae_stores';
// import { api, Element_obj_tbl_row } from 'aether_npm_lib';
import Element_obj_tbl_row from '$lib/element_obj_tbl_row.svelte';
import { post_object } from '$lib/api_post_object';
// *** Import Aether core components
// import Element_obj_tbl_row from './element_obj_tbl_row.svelte';
// *** Import Aether module variables and functions
// *** Import Aether module components
// *** Export/Exposed variables and functions for component
export let api_cfg: any;
export let show_textarea = true;
export let button_label = 'Run SQL!';
export let show_record_count = true;
export let remove_breaks = false;
export let run_on_load = false;
export let sql_statement: string;
export let sql_data = null;
export let as_list = false;
export let log_lvl = 1;
// *** Set initial variables
let ae_promises: key_val = {};
let sql_qry_result: any = null;
onMount(() => {
console.log('** Element Mounted: ** Element SQL Query');
if (run_on_load) {
console.log('Run On Load');
let result = handle_run_sql(sql_statement, sql_data, as_list, log_lvl)
.then((qry_result) => {
console.log('SQL Query Result:', qry_result);
sql_qry_result = qry_result;
return qry_result;
});
}
});
// const dispatch = createEventDispatcher();
async function handle_run_sql(qry, data, as_list=false, log_lvl=0) {
console.log('*** handle_run_sql() ***');
let sql_qry_data: key_val = {};
let endpoint = '/sql/select';
let params: key_val = {};
if (as_list) {
params['as_list'] = true;
}
if (log_lvl) {
console.log('Params:', params);
}
if (qry) {
} else {
return false;
}
if (log_lvl>1) {
console.log('Qry:', qry);
}
if (remove_breaks) {
sql_qry_data['sql_qry'] = qry.replace(/(\r\n|\n|\r)/gm, "");
} else {
sql_qry_data['sql_qry'] = qry;
}
sql_qry_data['sql_data'] = data;
if (log_lvl) {
console.log('SQL Qry Data:', sql_qry_data);
}
ae_promises.sql_qry_promise = await post_object({api_cfg: api_cfg, endpoint: endpoint, params: params, data: sql_qry_data, log_lvl: log_lvl});
if (log_lvl) {
console.log('SQL Query Results', ae_promises.sql_qry_promise);
}
return ae_promises.sql_qry_promise;
}
</script>
<section id="sql_qry" class="sql_qry">
{#if show_textarea}
<textarea
class="textarea"
bind:value={sql_statement}></textarea>
{/if}
<div class="text-center">
<button
type="button"
on:click={async () => {
sql_qry_result = await handle_run_sql(sql_statement, sql_data, as_list, log_lvl);
}}
class="btn btn-md variant-soft-primary hover:variant-ghost-primary"
>
{button_label}
</button>
</div>
{#if show_record_count && sql_qry_result && sql_qry_result.length}
<div>
Record count: <strong>{sql_qry_result.length}</strong>
</div>
{/if}
<div class="sql_statement_result">
{#await ae_promises.sql_qry_promise}
Getting results...
{:then}
{#if sql_qry_result && sql_qry_result.length}
<table class="table table-compact table-bordered table-striped table-hover min-w-min sql_qry_result text-xs">
<Element_obj_tbl_row row_header={true} obj={sql_qry_result[0]} primary_obj_li_type='' />
{#each sql_qry_result as record}
<Element_obj_tbl_row obj={record} primary_obj_li_type='' />
{/each}
</table>
{:else}
<div>Nothing to show yet...</div>
{/if}
{/await}
</div>
</section>
<style lang="postcss">
/* .sql_qry textarea {
width: 100%;
height: 8em;
} */
</style>

1
src/lib/index.ts Normal file
View File

@@ -0,0 +1 @@
// place files you want to import through the `$lib` alias in this folder.

View File

@@ -1,176 +0,0 @@
<script lang="ts">
import get_object from './api_get.js';
import delete_object from './api_delete.js';
// import InputElement from './input_element.svelte';
export let name: string;
export let account_id: string;
let log_client_viewing_list = Array();
//let log_client_viewing = Object();
let log_client_viewing = null;
//let request_promise = null;
let request_promise_list = null;
let request_promise_del = null;
function handle_get_log_client_viewing_obj_list() {
console.log('*** handle_get_log_client_viewing_obj_list() ***');
request_promise_list = get_log_client_viewing_obj_list();
}
async function get_log_client_viewing_obj_list() {
console.log('Request the log client viewing list...');
let endpoint = `/account/${account_id}/log/client_viewing/list`;
// let params = { from_datetime: '', to_datetime: '' };
let params = { };
let log_client_viewing_list_resp = await get_object({endpoint:endpoint, params:params, force_li:true});
console.log(log_client_viewing_list_resp);
log_client_viewing_list = log_client_viewing_list_resp;
}
async function get_log_client_viewing_obj(log_client_viewing_id) {
console.log('Request the log client viewing object...');
let endpoint = `log/client_viewing/${log_client_viewing_id}`;
let log_client_viewing_resp = await get_object({endpoint:endpoint});
console.log(log_client_viewing_resp);
log_client_viewing = log_client_viewing_resp;
}
function handle_delete_log_client_viewing_obj(log_client_viewing_id_random) {
console.log('*** handle_delete_log_client_viewing_obj() ***');
request_promise_del = delete_log_client_viewing_obj(log_client_viewing_id_random);
}
async function delete_log_client_viewing_obj(log_client_viewing_id_random) {
console.log('Delete the log client viewing object...');
let endpoint = `log/client_viewing/${log_client_viewing_id_random}`;
let log_client_viewing_obj_resp = await delete_object({endpoint:endpoint});
console.log(log_client_viewing_obj_resp);
}
</script>
<div>
<header>
<h1>{name}</h1>
</header>
<button on:click={handle_get_log_client_viewing_obj_list}>
Load Client Viewing Log Entries
</button>
<div class="log_client_viewing_obj_li">
{#await request_promise_list}
<div>waiting...</div>
{:then data}
<div>{data}</div>
{:catch error}
<div class="error">{error.message}</div>
{/await}
<ul>
{#each log_client_viewing_list as log_client_viewing}
<li key={log_client_viewing.log_client_viewing_id_random}>{log_client_viewing.name} {log_client_viewing.name} <button on:click={get_log_client_viewing_obj(log_client_viewing.log_client_viewing_id_random)}><span class="fas fa-trash"></span></button></li>
{/each}
</ul>
<table class="log_client_viewing_obj_tbl">
{#each log_client_viewing_list as log_client_viewing}
<tr key={log_client_viewing.log_client_viewing_id_random}>
<td>{log_client_viewing.external_client_id}</td>
<td>{log_client_viewing.name}</td>
<td>{log_client_viewing.page_load_on}</td>
<td>{log_client_viewing.authenticated_on}</td>
<td>{log_client_viewing.play_start_on_first}</td>
<td>{log_client_viewing.play_start_on_last}</td>
<td>{log_client_viewing.play_start_count}</td>
<td>{log_client_viewing.play_ended_on}</td>
<td>{log_client_viewing.play_ended_count}</td>
<td>{log_client_viewing.created_on}</td>
<td>{log_client_viewing.update_on}</td>
<button on:click={handle_delete_log_client_viewing_obj(log_client_viewing.log_client_viewing_id_random)}><span class="fas fa-trash"></span></button>
</tr>
{/each}
</table>
{#if log_client_viewing}
<div class="log_client_viewing_obj">
<div>Viewing something</div>
</div>
{:else}
<div>Nothing to see yet</div>
{/if}
</div>
<div class="log_client_viewing_obj_li">
{#await request_promise_list}
<div>waiting...</div>
{:then data}
<div>Data: {data}</div>
{:catch error}
<div class="error">{error.message}</div>
{/await}
<ul>
{#each log_client_viewing_list as log_client_viewing}
<li key={log_client_viewing.log_client_viewing_id_random}>{log_client_viewing.name}</li>
{/each}
</ul>
{#if log_client_viewing}
<div class="log_client_viewing_obj">
<h1>{log_client_viewing.name}</h1>
<div>{log_client_viewing.summary}</div>
<div>{log_client_viewing.content}</div>
<div>{log_client_viewing.description}</div>
<div>{log_client_viewing.created_on} {log_client_viewing.updated_on}</div>
</div>
{:else}
<div>Click an entry to view the details.</div>
{/if}
</div>
</div>
<style>
h1 {
color: hsla(0, 50%, 50%, 1);
/*text-transform: uppercase;*/
font-size: 4rem;
font-weight: 100;
}
.log_client_viewing_obj_tbl {
color: hsla(0, 0%, 0%, 1);
}
table {
border: solid thin hsla(0, 0%, 50%, 1);
border-collapse: collapse;
}
th, td {
border: solid thin hsla(0, 0%, 75%, 1);
border-collapse: collapse;
/* margin: 0; */
padding: .5rem;
}
tr:nth-child(even) {
background-color: hsla(0, 0%, 95%, 1);
}
tr:nth-child(odd) {
background-color: hsla(0, 0%, 85%, 1);
}
</style>

View File

@@ -1,260 +0,0 @@
<script lang="ts">
import { fade, fly } from 'svelte/transition';
import get_object from './api_get.js';
import delete_object from './api_delete.js';
// import InputElement from './input_element.svelte';
export let name: string;
export let account_id: string;
let log_client_viewing_li = Array();
$: log_client_viewing_li_length = log_client_viewing_li.length;
$: log_client_viewing_li_reviewed = log_client_viewing_li.filter(log_client_viewing_li => log_client_viewing_li.reviewed).length
//let log_client_viewing = Object();
// let log_client_viewing = null;
// let status_list_log_client_viewing = null;
// let status_delete_log_client_viewing = null;
//let request_promise = null;
let promise_request_li = null;
let promise_request_delete = null;
let promise_viewing_entry = null;
function handle_get_log_client_viewing_obj_list() {
console.log('*** handle_get_log_client_viewing_obj_list() ***');
promise_request_li = get_log_client_viewing_obj_list();
}
async function get_log_client_viewing_obj_list() {
console.log('Request the log client viewing list...');
let endpoint = `/account/${account_id}/log/client_viewing/list`;
// let params = { from_datetime: '', to_datetime: '' };
let params = { };
let log_client_viewing_li_resp = await get_object({endpoint:endpoint, params:params, force_li:true});
console.log(log_client_viewing_li_resp);
log_client_viewing_li = log_client_viewing_li_resp;
}
/*async function get_log_client_viewing_obj(log_client_viewing_id) {
console.log('Request the log client viewing object...');
let endpoint = `log/client_viewing/${log_client_viewing_id}`;
let log_client_viewing_resp = await get_object({endpoint:endpoint});
console.log(log_client_viewing_resp);
// status_list_log_client_viewing = log_client_viewing_resp;
}*/
function handle_delete_log_client_viewing_obj(rm_log_client_viewing) {
console.log('*** handle_delete_log_client_viewing_obj() ***');
if (confirm(`Remove ID ${rm_log_client_viewing.log_client_viewing_id_random}?`)) {
promise_request_delete = delete_log_client_viewing_obj(rm_log_client_viewing.log_client_viewing_id_random);
log_client_viewing_li = log_client_viewing_li.filter(log_client_viewing => log_client_viewing !== rm_log_client_viewing);
// console.log(log_client_viewing_li);
return true;
} else {
return false;
}
}
async function delete_log_client_viewing_obj(log_client_viewing_id_random) {
console.log('Delete the log client viewing object...');
let endpoint = `log/client_viewing/${log_client_viewing_id_random}`;
let log_client_viewing_obj_resp = await delete_object({endpoint:endpoint});
// console.log(log_client_viewing_obj_resp);
// status_delete_log_client_viewing = log_client_viewing_obj_resp;
}
function handle_view_log_client_viewing_obj(log_client_viewing) {
console.log('*** handle_view_log_client_viewing_obj() ***');
// if (confirm(`Entry ID ${log_client_viewing.log_client_viewing_id_random}?`)) {
promise_viewing_entry = log_client_viewing;
// promise_request_view = view_log_client_viewing_obj(rm_log_client_viewing.log_client_viewing_id_random);
// log_client_viewing_li = log_client_viewing_li.filter(log_client_viewing => log_client_viewing !== rm_log_client_viewing);
// console.log(log_client_viewing_li);
return true;
// } else {
// return false;
// }
}
function handle_promise_reset(reset_variable) {
reset_variable = null;
promise_viewing_entry = null;
}
// async function view_log_client_viewing_obj(log_client_viewing_id_random) {
// console.log('view the log client viewing object...');
// let endpoint = `log/client_viewing/${log_client_viewing_id_random}`;
// let log_client_viewing_obj_resp = await view_object({endpoint:endpoint});
// // console.log(log_client_viewing_obj_resp);
// // status_view_log_client_viewing = log_client_viewing_obj_resp;
// }
</script>
<div>
<header>
<h2>{name}</h2>
</header>
<button on:click={handle_get_log_client_viewing_obj_list}>
Load Client Viewing Log Entries
</button>
<div class="log_client_viewing_obj_li">
{#if promise_request_li}
{#await promise_request_li}
<div>Loading...</div>
{:then result}
<!-- <div>Loaded</div> -->
{:catch error}
<div class="error">{error.message}</div>
{/await}
<table class="table_borders log_client_viewing_obj_tbl table_alt_rows">
<tr>
<th>Rand ID</th>
<th>Email</th>
<th>Name</th>
<th>Page Load</th>
<th>Authenticated</th>
<th>Play Start First</th>
<th>Play Start Last</th>
<th>Play Start Count</th>
<th>Play Ended</th>
<th>Play Ended Count</th>
<th>Log Created</th>
<th>Log Updated</th>
<th>Entry</th>
</tr>
{#each log_client_viewing_li as log_client_viewing, index}
<tr key={log_client_viewing.log_client_viewing_id_random} class="record">
<!-- <td>{index}</td> -->
<td class="id_random">{log_client_viewing.log_client_viewing_id_random}</td>
<td>{#if log_client_viewing.external_client_id}{log_client_viewing.external_client_id}{/if}</td>
<td>{#if log_client_viewing.name}{log_client_viewing.name}{/if}</td>
<td>{iso_datetime_formatter(log_client_viewing.page_load_on,'datetime_short_month')}</td>
<td>{iso_datetime_formatter(log_client_viewing.authenticated_on,'datetime_short_month')}</td>
<td>{iso_datetime_formatter(log_client_viewing.play_start_on_first,'datetime_short_month')}</td>
<td>{iso_datetime_formatter(log_client_viewing.play_start_on_last,'datetime_short_month')}</td>
<td>{log_client_viewing.play_start_count}</td>
<td>{iso_datetime_formatter(log_client_viewing.play_ended_on,'datetime_short_month')}</td>
<td>{log_client_viewing.play_ended_count}</td>
<td>{iso_datetime_formatter(log_client_viewing.created_on,'datetime_short_month')}</td>
<td>{iso_datetime_formatter(log_client_viewing.updated_on,'datetime_iso_12_short_month')}</td>
<td>
<button on:click={handle_delete_log_client_viewing_obj(log_client_viewing)}><span class="fas fa-trash"></span></button>
<button on:click={handle_view_log_client_viewing_obj(log_client_viewing)}><span class="fas fa-eye"></span></button>
</td>
</tr>
{/each}
</table>
Count: {log_client_viewing_li_length}
{:else}
<div>Nothing to see yet</div>
{/if}
{#await promise_request_delete}
<div>Deleting...</div>
{:then result}
{:catch error}
<div class="error">{error.message}</div>
{/await}
{#if promise_viewing_entry}
<div transition:fade="{{ duration: 200 }}" class="modal_container">
<div class="modal_content">
<header class="modal_header">
<section class="modal_header_begin">
<h3 class="modal_title">{promise_viewing_entry.name} ({promise_viewing_entry.external_client_id})</h3>
<div>{promise_viewing_entry.log_client_viewing_id_random}</div>
</section>
<section class="modal_header_end">
<button on:click={handle_promise_reset(promise_viewing_entry)} class="modal_close"><span class="fas fa-window-close"></span> Close</button>
</section>
</header>
<section class="modal_body">
<div>Page Loaded: {iso_datetime_formatter(promise_viewing_entry.page_load_on,'datetime_short')}</div>
<div>Authenticated: {iso_datetime_formatter(promise_viewing_entry.authenticated_on,'datetime_short_month')}</div>
<div>Start: first: {#if promise_viewing_entry.play_start_on_first}{iso_datetime_formatter(promise_viewing_entry.play_start_on_first,'datetime_short_month')}{/if} {#if promise_viewing_entry.play_start_on_last}last: {iso_datetime_formatter(promise_viewing_entry.play_start_on_last,'datetime_short_month')}{/if} x{#if promise_viewing_entry.play_start_count}{promise_viewing_entry.play_start_count}{/if}</div>
<div>Pause: first: {iso_datetime_formatter(promise_viewing_entry.play_pause_on_first,'datetime_short_month')} last: {iso_datetime_formatter(promise_viewing_entry.play_pause_on_last,'datetime_short_month')} x{promise_viewing_entry.play_pause_count}</div>
<div>Seeked: first: {iso_datetime_formatter(promise_viewing_entry.play_seeked_on_first,'datetime_short_month')} last: {iso_datetime_formatter(promise_viewing_entry.play_seeked_on_last,'datetime_short_month')} x{promise_viewing_entry.play_seeked_count}</div>
<div>Ended: {iso_datetime_formatter(promise_viewing_entry.play_ended_on,'datetime_short_month')} x{promise_viewing_entry.play_ended_count}</div>
<div>Volume: {iso_datetime_formatter(promise_viewing_entry.play_volume_change_on,'datetime_short_month')} x{promise_viewing_entry.play_volume_change_count} vol: {promise_viewing_entry.play_volume}</div>
<div>Muted: {promise_viewing_entry.play_muted} x{promise_viewing_entry.play_muted_toggle_count}</div>
<div>Last Ping: {iso_datetime_formatter(promise_viewing_entry.last_ping,'datetime_short')}</div>
<div>Log Created/Updated: {iso_datetime_formatter(promise_viewing_entry.created_on,'datetime_short')} / {iso_datetime_formatter(promise_viewing_entry.updated_on,'datetime_short')}</div>
<div>
Client App:
<pre>
{format_json_string(promise_viewing_entry.client_app_json)}
</pre>
</div>
</section>
<footer class="modal_footer">
<section class="modal_footer_begin">
<div class="load_datetime"><span class="label">Loaded:</span> <span class="datetime">{new Date()}</span></div>
</section>
<section class="modal_footer_end">
<button on:click={handle_promise_reset(promise_viewing_entry)} class="modal_close"><span class="fas fa-window-close"></span> Close</button>
</section>
</footer>
</div>
</div>
{:else}
<div>Select an entry above</div>
{/if}
</div>
</div>
<style>
.log_client_viewing_obj_tbl tr:hover {
background-color: hsla(0, 25%, 90%, 1);
}
.log_client_viewing_obj_tbl {
font-size: .8rem;
}
.record .id_random {
font-size: .5rem;
}
/* .record_details {
display: fixed;
top: 1rem;
right: 1rem;
bottom: 1rem;
left: 1rem;
border: solid thin hsla(0, 0%, 50%, 1);
} */
</style>

View File

@@ -1,56 +0,0 @@
// import api from './api.js';
import App from './App.svelte';
import log_client_viewing_li from './log_client_viewing.svelte';
import membership_member_manage from './membership_member_manage.svelte';
import person from './person.svelte';
// import user from './user.svelte';
// <App />
if (document.getElementById('log_client_viewing_list_container')) {
const log_client_viewing_app = new log_client_viewing_li({
target: document.getElementById('log_client_viewing_list_container'),
props: {
'name': 'List Client Viewing Log',
'account_id': account_id,
}
});
}
if (document.getElementById('membership_member_manage_container')) {
const membership_member_manage_app = new membership_member_manage({
target: document.getElementById('membership_member_manage_container'),
props: {
'name': 'Membership Member Manage',
'account_id': account_id,
'membership_member_id': membership_member_id,
}
});
}
if (document.getElementById('person_container')) {
const person_app = new person({
target: document.getElementById('person_container'),
props: {
'name': 'Person',
'account_id': account_id,
'person_id': person_id,
}
});
}
// if (document.getElementById('user_container')) {
// const user_app = new user({
// target: document.getElementById('user_container'),
// props: {
// 'name': 'User',
// 'account_id': account_id,
// 'user_id': user_id,
// }
// });
// }
//export default app;
//export app_2;

View File

@@ -1,264 +0,0 @@
<script lang="ts">
import { fade, fly } from 'svelte/transition';
// import delete_object from './api_delete.js';
import get_object from './api_get.js';
import update_object from './api_patch.js';
export let name: string;
export let account_id: string;
export let membership_member_id: string;
let membership_member_obj_li = Array();
// let membership_member_obj = null;
let membership_member_obj_view = null;
let promise_request_obj_del = null;
// let promise_request_obj_get = null;
let promise_request_obj_li = null;
let promise_request_obj_up = null;
function handle_get_membership_member_obj_li() {
console.log('*** handle_get_membership_member_obj_li() ***');
promise_request_obj_li = get_membership_member_obj_li();
}
async function get_membership_member_obj_li() {
console.log('*** get_membership_member_obj_li() ***');
let endpoint = `/account/${account_id}/membership/member/list`;
let params = { inc_person: true, inc_user: true };
let membership_member_obj_li_resp = await get_object({endpoint:endpoint, params:params, force_li:true});
console.log(membership_member_obj_li_resp);
membership_member_obj_li = membership_member_obj_li_resp;
}
function handle_view_membership_member_obj(membership_member_obj) {
console.log('*** handle_view_membership_member_obj() ***');
membership_member_obj_view = membership_member_obj;
}
function handle_reset_view_membership_member_obj() {
console.log('*** handle_reset_view_membership_member_obj() ***');
membership_member_obj_view = null;
}
function handle_status_membership_member_obj(membership_member_obj, status) {
console.log('*** handle_status_membership_member_obj() ***');
// console.log(membership_member_obj);
// console.log(membership_member_obj_li.indexOf(membership_member_obj));
let index = membership_member_obj_li.indexOf(membership_member_obj);
// membership_member_obj_up = membership_member_obj_li[index];
let membership_member_id = membership_member_obj.membership_member_id_random;
let data = {}
// let status_name = null;
let current_datetime = new Date();
switch (status) {
case 'pending':
data = { 'status_id': 1, 'approved_on': null, 'start_on': null };
membership_member_obj_li[index].status_id = 1;
membership_member_obj_li[index].status_name = 'Pending';
membership_member_obj_li[index].approved_on = null;
membership_member_obj_li[index].start_on = null;
break;
case 'approve':
data = { 'status_id': 3, 'approved_on': current_datetime };
membership_member_obj_li[index].status_id = 3;
membership_member_obj_li[index].status_name = 'Approved';
membership_member_obj_li[index].approved_on = current_datetime;
break;
case 'reject':
data = { 'status_id': 4, 'approved_on': null, 'start_on': null };
membership_member_obj_li[index].status_id = 4;
membership_member_obj_li[index].status_name = 'Rejected';
membership_member_obj_li[index].approved_on = null;
membership_member_obj_li[index].start_on = null;
break;
case 'active':
data = { 'status_id': 5, 'start_on': current_datetime };
membership_member_obj_li[index].status_id = 5;
membership_member_obj_li[index].status_name = 'Active';
membership_member_obj_li[index].start_on = current_datetime;
if (!membership_member_obj_li[index].first_start_on) {
data['first_start_on'] = current_datetime;
membership_member_obj_li[index].first_start_on = current_datetime;
}
break;
}
promise_request_obj_up = update_membership_member_obj(membership_member_id, data);
// membership_member_obj.status_id = data['status_id'];
// membership_member_obj.status_name = status_name;
// membership_member_obj.approved_on = data['approved_on'];
// let array_index = membership_member_obj_li.indexOf(membership_member_obj);
// membership_member_obj_up.status_id = data['status_id'];
// membership_member_obj_up.status_name = status_name;
// membership_member_obj_up.approved_on = data['approved_on'];
// membership_member_obj_li = membership_member_obj_li.filter(log_client_viewing => log_client_viewing !== rm_log_client_viewing);
}
async function update_membership_member_obj(membership_member_id, data) {
console.log('*** update_membership_member_obj() ***');
let endpoint = `/membership/member/${membership_member_id}`;
let membership_member_obj_up_resp = await update_object({endpoint:endpoint, record:data});
console.log(membership_member_obj_up_resp);
// membership_member_obj_li = membership_member_obj_up_resp;
}
</script>
<div>
<header>
<h2>{name}</h2>
</header>
<button on:click={handle_get_membership_member_obj_li}>
Load Membership Member List
</button>
<div class="membership_member_obj_li">
{#if membership_member_obj_li}
{#await membership_member_obj_li}
<div>Loading...</div>
{:then result}
<!-- <div>Loaded</div> -->
{:catch error}
<div class="error">{error.message}</div>
{/await}
<table class="table_borders membership_member_obj_tbl table_alt_rows">
<tr>
<th>Actions</th>
<!-- <th>Index</th> -->
<th>ID</th>
<th>Type</th>
<th>Status</th>
<th>Name</th>
<th>Username</th>
<th>Email</th>
<th>Approved</th>
<th>First Start On</th>
<th>Current Start On</th>
</tr>
{#each membership_member_obj_li as membership_member_obj, index}
<tr key={membership_member_obj.membership_member_id_random} class="record">
<td>
<button on:click={handle_view_membership_member_obj(membership_member_obj)}><span class="fas fa-eye"></span></button>
</td>
<!-- <td>{index}</td> -->
<td class="id_random">{membership_member_obj.membership_member_id_random}</td>
<td class="type_name">{membership_member_obj.type_name}</td>
<td class="status_name">
{membership_member_obj.status_name}
{#if membership_member_obj.status_name === 'Pending'}
<button on:click={handle_status_membership_member_obj(membership_member_obj, 'approve')} title="Set to approved"><span class="fas fa-user-check"></span></button>
<button on:click={handle_status_membership_member_obj(membership_member_obj, 'reject')} title="Set to rejected"><span class="fas fa-user-times"></span></button>
{:else if membership_member_obj.status_name === 'Rejected'}
<button on:click={handle_status_membership_member_obj(membership_member_obj, 'pending')} title="Set to pending"><span class="fas fa-user-lock"></span></button>
<button on:click={handle_status_membership_member_obj(membership_member_obj, 'reject')} title="Set to rejected"><span class="fas fa-user-times"></span></button>
{:else if membership_member_obj.status_name === 'Approved'}
<button on:click={handle_status_membership_member_obj(membership_member_obj, 'reject')} title="Set to rejected"><span class="fas fa-user-times"></span></button>
<button on:click={handle_status_membership_member_obj(membership_member_obj, 'active')} title="Set to active"><span class="fas fa-user-check"></span></button>
{/if}
</td>
<td class="full_name">{membership_member_obj.person.full_name}</td>
<td class="username">{membership_member_obj.user.username}</td>
<td class="email">{membership_member_obj.user.email}</td>
<td class="approved_on">{iso_datetime_formatter(membership_member_obj.approved_on,'datetime_short')}</td>
<td class="first_start_on">{iso_datetime_formatter(membership_member_obj.first_start_on,'datetime_short')}</td>
<td class="start_on">{iso_datetime_formatter(membership_member_obj.start_on,'datetime_short')}</td>
</tr>
{/each}
</table>
{:else}
<div>Nothing loaded yet</div>
{/if}
{#await promise_request_obj_del}
<div>Deleting...</div>
{:then result}
{:catch error}
<div class="error">{error.message}</div>
{/await}
{#await promise_request_obj_up}
<div>Updating...</div>
{:then result}
{:catch error}
<div class="error">{error.message}</div>
{/await}
{#if membership_member_obj_view}
<div transition:fade="{{ duration: 200 }}" class="modal_container">
<div class="modal_content">
<header class="modal_header">
<section class="modal_header_begin">
<h3 class="modal_title">{membership_member_obj_view.person.full_name} ({membership_member_obj_view.user.username})</h3>
<div>{membership_member_obj_view.membership_member_id_random}</div>
</section>
<section class="modal_header_end">
<button on:click={handle_reset_view_membership_member_obj(membership_member_obj_view)} class="modal_close"><span class="fas fa-window-close"></span> Close</button>
</section>
</header>
<section class="modal_body">
<div>Approved on: {iso_datetime_formatter(membership_member_obj_view.approved_on,'datetime_short')}</div>
<div>Created/Updated: {iso_datetime_formatter(membership_member_obj_view.created_on,'datetime_short')} / {iso_datetime_formatter(membership_member_obj_view.updated_on,'datetime_short')}</div>
</section>
<footer class="modal_footer">
<section class="modal_footer_begin">
<div class="load_datetime"><span class="label">Loaded:</span> <span class="datetime">{new Date()}</span></div>
</section>
<section class="modal_footer_end">
<button on:click={handle_reset_view_membership_member_obj(membership_member_obj_view)} class="modal_close"><span class="fas fa-window-close"></span> Close</button>
</section>
</footer>
</div>
</div>
{:else}
<div>Select an entry above</div>
{/if}
</div>
</div>
<style>
.membership_member_obj_tbl tr:hover {
background-color: hsla(0, 25%, 90%, 1);
}
.membership_member_obj_tbl {
font-size: .8rem;
}
.record .id_random {
font-size: .5rem;
}
/* .record_details {
display: fixed;
top: 1rem;
right: 1rem;
bottom: 1rem;
left: 1rem;
border: solid thin hsla(0, 0%, 50%, 1);
} */
</style>

128
src/parent_iframe.html Normal file
View File

@@ -0,0 +1,128 @@
<!-- BEGIN: Aether apps for iframe -->
<script>
let parent_ae_app_iframe_url = 'https://dev-chow.oneskyit.com/';
let parent_ae_params = new URLSearchParams(document.location.search);
let parent_ae_slct_account_id = parent_ae_params.get('account_id');
let parent_ae_slct_event_id = parent_ae_params.get('event_id');
let parent_ae_slct_event_presenter_id = parent_ae_params.get('event_presenter_id');
let parent_ae_slct_sponsorship_id = parent_ae_params.get('sponsorship_id');
let parent_ae_slct_sponsorship_cfg_id = parent_ae_params.get('sponsorship_cfg_id');
let parent_ae_slct_obj_type = parent_ae_params.get('ae_type');
let parent_ae_slct_obj_id = parent_ae_params.get('ae_id');
let parent_ae_iframe_height = null;
if (parent_ae_slct_event_id && parent_ae_slct_event_presenter_id) {
parent_ae_app_iframe_url = `${parent_ae_app_iframe_url}events_speakers?event_id=${parent_ae_slct_event_id}`;
} else if (parent_ae_slct_event_id) {
parent_ae_app_iframe_url = `${parent_ae_app_iframe_url}events_speakers?event_id=${parent_ae_slct_event_id}`;
} else if (parent_ae_slct_event_presenter_id) {
parent_ae_app_iframe_url = `${parent_ae_app_iframe_url}events_speakers?event_presenter_id=${parent_ae_slct_event_presenter_id}`;
}
if (parent_ae_slct_sponsorship_id && parent_ae_slct_sponsorship_cfg_id) {
parent_ae_app_iframe_url = `${parent_ae_app_iframe_url}/sponsorships?sponsorship_id=${parent_ae_slct_sponsorship_id}&sponsorship_cfg_id=${parent_ae_slct_sponsorship_cfg_id}`;
} else if (parent_ae_slct_sponsorship_id) {
parent_ae_app_iframe_url = `${parent_ae_app_iframe_url}sponsorships?sponsorship_id=${parent_ae_slct_sponsorship_id}`;
} else if (parent_ae_slct_sponsorship_cfg_id) {
parent_ae_app_iframe_url = `${parent_ae_app_iframe_url}sponsorships?sponsorship_cfg_id=${parent_ae_slct_sponsorship_cfg_id}`;
}
if (parent_ae_slct_obj_type && parent_ae_slct_obj_id) {
parent_ae_app_iframe_url = `${parent_ae_app_iframe_url}&${parent_ae_slct_obj_type}_id=${parent_ae_slct_obj_id}`;
}
if (parent_ae_app_iframe_url == 'https://dev-chow.oneskyit.com/') {
parent_ae_app_iframe_url = `${parent_ae_app_iframe_url}?iframe=true`;
} else {
parent_ae_app_iframe_url = `${parent_ae_app_iframe_url}&iframe=true`;
}
console.log(`AE parent iframe URL: ${parent_ae_app_iframe_url}`);
window.addEventListener('message', function(event) {
console.log('AE iframe parent: Message received from the child:', event.data);
if (event.data) {
if (event.data.iframe_height) {
parent_ae_iframe_height = event.data.iframe_height;
console.log(`Got AE iframe height: ${parent_ae_iframe_height}`);
let parent_ae_iframe_element = document.getElementById('ae_iframe');
// parent_ae_iframe_element.style.height = parent_ae_iframe_height;
parent_ae_iframe_element.style.height = `${parent_ae_iframe_height+50}px`;
}
const url = new URL(location);
// Check if event_id is defined in the message
if (event.data.event_id !== undefined) {
console.log(`Got AE Event ID: ${event.data.event_id}`);
parent_ae_slct_event_id = event.data.event_id;
if (event.data.event_id) {
url.searchParams.set('event_id', event.data.event_id);
} else {
url.searchParams.delete('event_id');
}
history.pushState({}, '', url);
}
// Check if event_presenter_id is defined in the message
if (event.data.event_presenter_id !== undefined) {
console.log(`Got AE Event Presenter ID: ${event.data.event_presenter_id}`);
parent_ae_slct_event_presenter_id = event.data.event_presenter_id;
if (event.data.event_presenter_id) {
url.searchParams.set('event_presenter_id', event.data.event_presenter_id);
} else {
url.searchParams.delete('event_presenter_id');
}
history.pushState({}, '', url);
}
// Check if sponsorship_id is defined in the message
if (event.data.sponsorship_id !== undefined) {
console.log(`Got AE Sponsorship ID: ${event.data.sponsorship_id}`);
parent_ae_slct_sponsorship_id = event.data.sponsorship_id;
if (event.data.sponsorship_id) {
url.searchParams.set('sponsorship_id', event.data.sponsorship_id);
} else {
url.searchParams.delete('sponsorship_id');
}
history.pushState({}, '', url);
}
// Check if sponsorship_cfg_id is defined in the message
if (event.data.sponsorship_cfg_id !== undefined) {
console.log(`Got AE Sponsorship Config ID: ${event.data.sponsorship_cfg_id}`);
parent_ae_slct_sponsorship_cfg_id = event.data.sponsorship_cfgt_id;
if (event.data.sponsorship_cfg_id) {
url.searchParams.set('sponsorship_cfg_id', event.data.sponsorship_cfg_id);
} else {
url.searchParams.delete('sponsorship_cfg_id');
}
history.pushState({}, '', url);
}
} else {
console.log(`No data in AE iframe child message? ${event}`);
}
});
document.addEventListener("DOMContentLoaded", () => {
console.log('Parent of AE iframe is ready!');
console.log(`AE parent iframe URL: ${parent_ae_app_iframe_url}`);
let parent_ae_iframe_element = document.getElementById('ae_iframe');
console.log('AE parent iframe element', parent_ae_iframe_element);
parent_ae_iframe_element.src = parent_ae_app_iframe_url;
});
console.log('AE iframe parent scripts run');
</script>
<p><iframe width="100%" height="750" style="min-height: 600px; max-height: 100%;" id="ae_iframe" src="" class="ae_parent_iframe"></iframe></p>
<!-- END: Aether apps for iframe -->

View File

@@ -1,342 +0,0 @@
<script lang="ts">
import { onMount } from 'svelte';
import { fade, fly } from 'svelte/transition';
// import delete_object from './api_delete.js';
import get_object from './api_get.js';
// import post_object from './api_post.js';
import patch_object from './api_patch.js';
import html_template from './html_input_render_templates.js';
import Input_element from './input_element.svelte';
export let name: string;
export let account_id: string;
export let person_id: string;
let person_obj = null;
let person_obj_get_promise = null;
let person_obj_up_promise = null;
let person_obj_edit = false;
let given_name = null;
let person_given_name_template = { name: 'given_name', label: 'Given name', type: 'text' };
let person_middle_name_template = { name: 'middle_name', label: 'Middle name', type: 'text' };
let person_family_name_template = { name: 'family_name', label: 'Family name', type: 'text' };
let contact_obj_edit = false;
let email = null;
let address_obj_edit = false;
let line_1 = false;
let person_data = null;
// let promise_request_obj_del = null;
// let promise_request_obj_get = null;
// let promise_request_obj_li = null;
let promise_request_obj_up = null;
onMount(() => {
console.log('The component has mounted');
person_obj_get_promise = get_person_obj(person_id);
/* const interval = setInterval(() => {
console.log('beep');
}, 1000); */
});
function handle_get_person_obj(person_id) {
console.log('*** handle_get_person_obj() ***');
person_obj_get_promise = get_person_obj(person_id);
}
async function get_person_obj(person_id) {
console.log('*** get_person_obj() ***');
let endpoint = `/person/${person_id}`;
let params = { inc_address: true, inc_contact: true, inc_membership_member: true };
let person_obj_get_resp = await get_object({endpoint:endpoint, params:params});
person_obj = person_obj_get_resp;
given_name = person_obj.given_name;
email = person_obj.contact.email;
line_1 = person_obj.contact.address.line_1;
return true;
}
function handle_update_person_obj() {
console.log('*** handle_update_person_obj() ***');
person_obj_up_promise = update_person_obj(person_id, person_data);
}
async function update_person_obj(person_id, person_data) {
console.log('*** update_person_obj() ***');
let endpoint = `/person/${person_id}`;
let params = { return_obj: true };
let person_obj_up_resp = await patch_object({endpoint:endpoint, params:params, record:person_data});
console.log(person_obj_up_resp);
person_obj = { ...person_obj, ...person_obj_up_resp };
return true;
}
function handle_edit_person(value) {
console.log('*** handle_edit_person() ***');
person_obj_edit = true;
}
function handle_cancel_person() {
console.log('*** handle_cancel_person() ***');
person_obj_edit = false;
}
function handle_save_person(event) {
console.log('*** handle_save_person() ***');
console.log(event);
console.log(event.target);
console.log(event.target.given_name.value);
console.log(event.target.family_name.value);
// person_id = event.target.person_id.value;
let person_data = {};
person_data['given_name'] = event.target.given_name.value;
person_data['middle_name'] = event.target.middle_name.value;
person_data['family_name'] = event.target.family_name.value;
let name_li = process_person_name(person_data);
person_data['title'] = event.target.title.value;
person_data['tagline'] = event.target.tagline.value;
person_data['organization_name'] = event.target.organization_name.value;
person_data['notes'] = event.target.notes.value;
person_data = Object.assign(person_data, name_li);
console.log(person_data);
person_obj_up_promise = update_person_obj(person_id, person_data);
// person_obj_edit = true;
}
function handle_delete_person(value) {
console.log('*** handle_delete_person() ***');
// person_obj_edit = true;
}
function handle_edit_contact(value) {
console.log('*** handle_edit_contact() ***');
contact_obj_edit = true;
}
function handle_cancel_contact(value) {
console.log('*** handle_cancel_contact() ***');
contact_obj_edit = false;
}
function handle_save_contact(value) {
console.log('*** handle_save_contact() ***');
}
function handle_delete_contact(value) {
console.log('*** handle_delete_contact() ***');
}
function handle_edit_address(value) {
console.log('*** handle_edit_address() ***');
address_obj_edit = true;
}
function handle_cancel_address(value) {
console.log('*** handle_cancel_address() ***');
address_obj_edit = false;
}
function handle_save_address(value) {
console.log('*** handle_save_address() ***');
}
function handle_delete_address(value) {
console.log('*** handle_delete_address() ***');
}
function test_fun() {
console.log('*** test_fun() ***');
return false;
}
</script>
<div>
<header>
<h2>{name}</h2>
</header>
<div class="person_obj">
<button on:click={handle_get_person_obj(person_id)}>
Load Person
</button>
{#await person_obj_get_promise}
<!-- promise is pending -->
<div>Loading...</div>
{:then result}
<!-- promise was fulfilled -->
{#if person_obj}
<section class="person_obj obj">
{#if person_obj_edit == true}
<form on:submit|preventDefault={handle_save_person} class="" on:keydown={e => e.key === 'Escape' && handle_cancel_person}>
<input value={person_obj.person_id_random} type="hidden" id="person__id_random--{person_obj.person_id_random}" name="id_random" />
<fieldset class="">
<legend>Name</legend>
<Input_element {...html_template['person']['given_name']} id_random={person_obj.person_id_random} value={person_obj.given_name} />
<Input_element {...html_template['person']['middle_name']} id_random={person_obj.person_id_random} value={person_obj.middle_name} />
<Input_element {...html_template['person']['family_name']} id_random={person_obj.person_id_random} value={person_obj.family_name} />
</fieldset>
<Input_element {...html_template['person']['title']} id_random={person_obj.person_id_random} value={person_obj.title} />
<Input_element {...html_template['person']['tagline']} id_random={person_obj.person_id_random} value={person_obj.tagline} />
<Input_element {...html_template['person']['organization_name']} id_random={person_obj.person_id_random} value={person_obj.organization_name} />
<Input_element {...html_template['person']['notes']} id_random={person_obj.person_id_random} value={person_obj.notes} />
<div class="edit_options">
<button class="btn person-cancel" on:click={handle_cancel_person} type="button">
Cancel<span class="visually_hidden">name change</span>
</button>
<button class="btn btn__primary person-edit" type="submit" disabled={!given_name}>
Save<span class="visually_hidden">name change</span>
</button>
</div>
</form>
Full name: {person_obj.full_name}
{:else}
Name: {person_obj.full_name} {person_obj.given_name} {person_obj.middle_name} {person_obj.family_name}
Organization name {person_obj.organization_name}
<div class="edit_options">
<button type="button" class="btn" on:click={handle_edit_person}>
Edit<span class="visually_hidden"> person</span>
</button>
<button type="button" class="btn btn__danger" on:click={handle_delete_person}>
Delete<span class="visually_hidden"> person</span>
</button>
</div>
{/if}
<section class="contact_obj obj">
{#if contact_obj_edit == true}
<form on:submit|preventDefault={handle_save_contact} class="" on:keydown={e => e.key === 'Escape' && handle_cancel_contact}>
<input value={person_obj.contact.contact_id_random} type="hidden" id="contact__id_random--{person_obj.contact.contact_id_random}" name="id_random" />
<label for="contact__email--{person_obj.contact.contact_id_random}" class="">Email</label>
<input bind:value={email} type="text" id="contact__email--{person_obj.contact.contact_id_random}" autoComplete="off" class="" />
<div class="edit_options">
<button class="btn contact-cancel" on:click={handle_cancel_contact} type="button">
Cancel<span class="visually_hidden">contact change</span>
</button>
<button class="btn btn__primary contact-edit" type="submit" disabled={!email}>
Save<span class="visually_hidden">contact change</span>
</button>
</div>
</form>
{:else}
Email: {person_obj.contact.email}
<div class="edit_options">
<button type="button" class="btn" on:click={handle_edit_contact}>
Edit<span class="visually_hidden"> contact</span>
</button>
<button type="button" class="btn btn__danger" on:click={handle_delete_contact}>
Delete<span class="visually_hidden"> contact</span>
</button>
</div>
{/if}
</section>
<section class="address_obj obj">
{#if address_obj_edit == true}
<form on:submit|preventDefault={handle_save_address} class="" on:keydown={e => e.key === 'Escape' && handle_cancel_address}>
<input value={person_obj.contact.address.address_id_random} type="hidden" id="address__id_random--{person_obj.contact.address.address_id_random}" name="id_random" />
<label for="address__line_1--{person_obj.contact.address.address_id_random}" class="">Line 1</label>
<input bind:value={line_1} type="text" id="address__line_1--{person_obj.contact.address.address_id_random}" autoComplete="off" class="" />
<div class="edit_options">
<button class="btn address-cancel" on:click={handle_cancel_address} type="button">
Cancel<span class="visually_hidden">address change</span>
</button>
<button class="btn btn__primary address-edit" type="submit" disabled={!line_1}>
Save<span class="visually_hidden">address change</span>
</button>
</div>
</form>
{:else}
Line 1: {person_obj.contact.address.line_1}
City: {person_obj.contact.address.city}
State/Province: {person_obj.contact.address.country_subdivision_name}
<div class="edit_options">
<button type="button" class="btn" on:click={handle_edit_address}>
Edit<span class="visually_hidden"> address</span>
</button>
<button type="button" class="btn btn__danger" on:click={handle_delete_address}>
Delete<span class="visually_hidden"> address</span>
</button>
</div>
{/if}
</section>
</section> <!-- END section contact_obj -->
{:else}
<div>Nothing loaded yet</div>
{/if}
{:catch error}
<!-- promise was rejected -->
<div class="error">{error.message}</div>
{/await}
{#await promise_request_obj_up}
<div>Updating...</div>
{:then result}
{:catch error}
<div class="error">{error.message}</div>
{/await}
</div>
</div>
<style>
section.obj {
margin: 1rem 0rem;
padding: .5rem .5rem;
}
.person_obj {
border: solid thin hsla(0, 25%, 90%, 1);
}
.contact_obj {
border: solid thin hsla(0, 25%, 90%, 1);
}
.address_obj{
border: solid thin hsla(0, 25%, 90%, 1);
}
</style>

View File

@@ -1,322 +0,0 @@
<script lang="ts">
import { onMount } from 'svelte';
import { fade, fly } from 'svelte/transition';
// import delete_object from './api_delete.js';
import get_object from './api_get.js';
// import post_object from './api_post.js';
import patch_object from './api_patch.js';
export let name: string;
export let account_id: string;
export let person_id: string;
let person_obj = null;
let person_obj_get_promise = null;
let person_obj_up_promise = null;
let person_obj_edit = false;
let given_name = null;
let contact_obj_edit = false;
let email = null;
let address_obj_edit = false;
let line_1 = false;
let person_data = null;
// let promise_request_obj_del = null;
// let promise_request_obj_get = null;
// let promise_request_obj_li = null;
let promise_request_obj_up = null;
onMount(() => {
console.log('The component has mounted');
person_obj_get_promise = get_person_obj(person_id);
/* const interval = setInterval(() => {
console.log('beep');
}, 1000); */
});
function handle_get_person_obj(person_id) {
console.log('*** handle_get_person_obj() ***');
person_obj_get_promise = get_person_obj(person_id);
}
async function get_person_obj(person_id) {
console.log('*** get_person_obj() ***');
let endpoint = `/person/${person_id}`;
let params = { inc_address: true, inc_contact: true, inc_membership_member: true };
let person_obj_get_resp = await get_object({endpoint:endpoint, params:params});
person_obj = person_obj_get_resp;
given_name = person_obj.given_name;
email = person_obj.contact.email;
line_1 = person_obj.contact.address.line_1;
return true;
}
function handle_update_person_obj() {
console.log('*** handle_update_person_obj() ***');
person_obj_up_promise = update_person_obj(person_id, person_data);
}
async function update_person_obj(person_id, person_data) {
console.log('*** update_person_obj() ***');
let endpoint = `/person/${person_id}`;
let params = { return_obj: true };
let person_obj_up_resp = await patch_object({endpoint:endpoint, params:params, record:person_data});
console.log(person_obj_up_resp);
person_obj = { ...person_obj, ...person_obj_up_resp };
return true;
}
function handle_edit_person(value) {
console.log('*** handle_edit_person() ***');
person_obj_edit = true;
}
function handle_cancel_person() {
console.log('*** handle_cancel_person() ***');
person_obj_edit = false;
}
function handle_save_person(event) {
console.log('*** handle_save_person() ***');
console.log(event);
console.log(event.target);
console.log(event.target.given_name.value);
console.log(event.target.family_name.value);
// person_id = event.target.person_id.value;
let person_data = {};
person_data['given_name'] = event.target.given_name.value;
person_data['middle_name'] = event.target.middle_name.value;
person_data['family_name'] = event.target.family_name.value;
console.log(person_data);
// person_data['full_name'] = `${event.target.given_name.value} ${event.target.family_name.value}`;
let name_li = process_person_name(person_data);
// person_data = { ...person_data, name_li };
person_data = Object.assign(person_data, name_li);
console.log(person_data);
person_obj_up_promise = update_person_obj(person_id, person_data);
// person_obj_edit = true;
}
function handle_delete_person(value) {
console.log('*** handle_delete_person() ***');
// person_obj_edit = true;
}
function handle_edit_contact(value) {
console.log('*** handle_edit_contact() ***');
contact_obj_edit = true;
}
function handle_cancel_contact(value) {
console.log('*** handle_cancel_contact() ***');
contact_obj_edit = false;
}
function handle_save_contact(value) {
console.log('*** handle_save_contact() ***');
}
function handle_delete_contact(value) {
console.log('*** handle_delete_contact() ***');
}
function handle_edit_address(value) {
console.log('*** handle_edit_address() ***');
address_obj_edit = true;
}
function handle_cancel_address(value) {
console.log('*** handle_cancel_address() ***');
address_obj_edit = false;
}
function handle_save_address(value) {
console.log('*** handle_save_address() ***');
}
function handle_delete_address(value) {
console.log('*** handle_delete_address() ***');
}
function test_fun() {
console.log('*** test_fun() ***');
return false;
}
</script>
<div>
<header>
<h2>{name}</h2>
</header>
<div class="person_obj">
<button on:click={handle_get_person_obj(person_id)}>
Load Person
</button>
{#await person_obj_get_promise}
<!-- promise is pending -->
<div>Loading...</div>
{:then result}
<!-- promise was fulfilled -->
{#if person_obj}
<section class="person_obj">
{#if person_obj_edit == true}
<form on:submit|preventDefault={handle_save_person} class="" on:keydown={e => e.key === 'Escape' && handle_cancel_person}>
<input value={person_obj.person_id_random} type="hidden" id="person__id_random--{person_obj.person_id_random}" name="id_random" />
<label for="person__given_name--{person_obj.person_id_random}" class="">Given Name</label>
<input bind:value={given_name} type="text" id="person__given_name--{person_obj.person_id_random}" name="given_name" autoComplete="off" class="" />
<label for="person__middle_name--{person_obj.person_id_random}" class="">Middle Name</label>
<input value={person_obj.middle_name} type="text" id="person__middle_name--{person_obj.person_id_random}" name="middle_name" autoComplete="off" class="" />
<label for="person__family_name--{person_obj.person_id_random}" class="">Family Name</label>
<input value={person_obj.family_name} type="text" id="person__family_name--{person_obj.person_id_random}" name="family_name" autoComplete="off" class="" />
<div class="edit_options">
<button class="btn person-cancel" on:click={handle_cancel_person} type="button">
Cancel<span class="visually_hidden">name change</span>
</button>
<button class="btn btn__primary person-edit" type="submit" disabled={!given_name}>
Save<span class="visually_hidden">name change</span>
</button>
</div>
</form>
Full name: {person_obj.full_name}
{:else}
Name: {person_obj.full_name} {person_obj.given_name} {person_obj.middle_name} {person_obj.family_name}
Organization name {person_obj.organization_name}
<div class="edit_options">
<button type="button" class="btn" on:click={handle_edit_person}>
Edit<span class="visually_hidden"> person</span>
</button>
<button type="button" class="btn btn__danger" on:click={handle_delete_person}>
Delete<span class="visually_hidden"> person</span>
</button>
</div>
{/if}
<section class="contact_obj">
{#if contact_obj_edit == true}
<form on:submit|preventDefault={handle_save_contact} class="" on:keydown={e => e.key === 'Escape' && handle_cancel_contact}>
<input value={person_obj.contact.contact_id_random} type="hidden" id="contact__id_random--{person_obj.contact.contact_id_random}" name="id_random" />
<label for="contact__email--{person_obj.contact.contact_id_random}" class="">Email</label>
<input bind:value={email} type="text" id="contact__email--{person_obj.contact.contact_id_random}" autoComplete="off" class="" />
<div class="edit_options">
<button class="btn contact-cancel" on:click={handle_cancel_contact} type="button">
Cancel<span class="visually_hidden">contact change</span>
</button>
<button class="btn btn__primary contact-edit" type="submit" disabled={!email}>
Save<span class="visually_hidden">contact change</span>
</button>
</div>
</form>
{:else}
Email: {person_obj.contact.email}
<div class="edit_options">
<button type="button" class="btn" on:click={handle_edit_contact}>
Edit<span class="visually_hidden"> contact</span>
</button>
<button type="button" class="btn btn__danger" on:click={handle_delete_contact}>
Delete<span class="visually_hidden"> contact</span>
</button>
</div>
{/if}
</section>
<section class="address_obj">
{#if address_obj_edit == true}
<form on:submit|preventDefault={handle_save_address} class="" on:keydown={e => e.key === 'Escape' && handle_cancel_address}>
<input value={person_obj.contact.address.address_id_random} type="hidden" id="address__id_random--{person_obj.contact.address.address_id_random}" name="id_random" />
<label for="address__line_1--{person_obj.contact.address.address_id_random}" class="">Line 1</label>
<input bind:value={line_1} type="text" id="address__line_1--{person_obj.contact.address.address_id_random}" autoComplete="off" class="" />
<div class="edit_options">
<button class="btn address-cancel" on:click={handle_cancel_address} type="button">
Cancel<span class="visually_hidden">address change</span>
</button>
<button class="btn btn__primary address-edit" type="submit" disabled={!line_1}>
Save<span class="visually_hidden">address change</span>
</button>
</div>
</form>
{:else}
Line 1: {person_obj.contact.address.line_1}
City: {person_obj.contact.address.city}
State/Province: {person_obj.contact.address.country_subdivision_name}
<div class="edit_options">
<button type="button" class="btn" on:click={handle_edit_address}>
Edit<span class="visually_hidden"> address</span>
</button>
<button type="button" class="btn btn__danger" on:click={handle_delete_address}>
Delete<span class="visually_hidden"> address</span>
</button>
</div>
{/if}
</section>
</section> <!-- END section contact_obj -->
{:else}
<div>Nothing loaded yet</div>
{/if}
{:catch error}
<!-- promise was rejected -->
<div class="error">{error.message}</div>
{/await}
{#await promise_request_obj_up}
<div>Updating...</div>
{:then result}
{:catch error}
<div class="error">{error.message}</div>
{/await}
</div>
</div>
<style>
.person_obj {
border: solid thin hsla(0, 25%, 90%, 1);
}
.contact_obj {
border: solid thin hsla(0, 25%, 90%, 1);
}
.address_obj{
border: solid thin hsla(0, 25%, 90%, 1);
}
</style>

View File

@@ -0,0 +1,11 @@
// export const ssr = false;
// export const prerender = true
// export const prerender = false;
// export const trailingSlash = 'always'; // 'never' | 'always' | 'ignore'
// import { TESTING } from '$env/static/private';
// console.log(`Aether Config - TESTING:`, TESTING);
// import { PRIVATE_TESTING } from '$env/static/private';
// console.log(`Aether Config - TESTING:`, PRIVATE_TESTING);

527
src/routes/+layout.svelte Normal file
View File

@@ -0,0 +1,527 @@
<script lang="ts">
/** @type {import('./$types').LayoutData} */
export let data: any;
let log_lvl = 0;
// console.log(`ae_ Svelte root +layout data:`, data);
import { onMount } from 'svelte';
import '../app.postcss';
import { AppShell, AppBar, initializeStores } from '@skeletonlabs/skeleton';
// Initialize the stores for Drawer, Modal, and Toast so they work throughout the app.
initializeStores();
import { Modal } from '@skeletonlabs/skeleton';
import type {
// DrawerSettings, DrawerComponent, DrawerStore,
ModalSettings, ModalComponent, ModalStore
} from '@skeletonlabs/skeleton';
// const drawerStore = getDrawerStore();
// import ModalComponentEditSponsorshipObj from './sponsorships/10_edit_modal__sponsorship_obj.svelte';
const modalRegistry: Record<string, ModalComponent> = {
// Set a unique modal ID, then pass the component reference
// modalComponentEditSponsorshipObj: { ref: ModalComponentEditSponsorshipObj },
// modalComponentTwo: { ref: ModalComponentTwo },
// ...
};
// Highlight JS
import hljs from 'highlight.js/lib/core';
import 'highlight.js/styles/github-dark.css';
// import type { Writable } from 'svelte/store';
// import { get } from 'svelte/store';
import { browser } from '$app/environment';
// import { goto } from '$app/navigation';
// import { page } from "$app/stores";
import { localStorageStore, storeHighlightJs } from '@skeletonlabs/skeleton';
import xml from 'highlight.js/lib/languages/xml'; // for HTML
import css from 'highlight.js/lib/languages/css';
import javascript from 'highlight.js/lib/languages/javascript';
import typescript from 'highlight.js/lib/languages/typescript';
hljs.registerLanguage('xml', xml); // for HTML
hljs.registerLanguage('css', css);
hljs.registerLanguage('javascript', javascript);
hljs.registerLanguage('typescript', typescript);
storeHighlightJs.set(hljs);
// Floating UI for Popups
import { computePosition, autoUpdate, flip, shift, offset, arrow } from '@floating-ui/dom';
import { storePopup } from '@skeletonlabs/skeleton';
storePopup.set({ computePosition, autoUpdate, flip, shift, offset, arrow });
// import { api } from '$lib/api';
import { ae_loc, ae_sess, ae_api, slct, slct_trigger } from '$lib/ae_stores';
import { events_loc, events_slct } from '$lib/ae_events_stores';
import type { key_val } from '$lib/ae_stores';
// console.log($ae_loc, $ae_sess, $ae_api);
import Element_access_type from '$lib/element_access_type.svelte';
import Element_app_cfg from '$lib/element_app_cfg.svelte';
import Element_data_store from '$lib/element_data_store.svelte';
// let account_id = localStorage.getItem('ae_account_id');
// console.log(`account_id = `, account_id);
// Quickly save the data passed from the parent(s) to the Svelte stores, localStorage, and other. This should catch anything that is a child of this layout.svelte file.
$slct.account_id = data.account_id;
console.log(`*ae_root +layout.svelte* $slct.account_id = `, $slct.account_id);
let ae_acct = data[$slct.account_id];
// console.log(`*ae_root +layout.svelte* ae_acct = `, ae_acct);
// let ae_acct = data.ae_acct;
// $ae_api = ae_acct.api;
// $ae_loc = ae_acct.loc;
$ae_api = {
...$ae_api,
...ae_acct.api,
}
// console.log(`$ae_api = `, $ae_api);
$ae_loc = {
...$ae_loc,
...ae_acct.loc,
}
// console.log(`$ae_loc = `, $ae_loc);
$slct = {
...$slct,
...ae_acct.slct,
}
// console.log(`$slct = `, $slct);
if ($ae_loc?.site_cfg_json.slct__event_id) {
$events_slct.event_id = $ae_loc.site_cfg_json.slct__event_id;
$events_loc.event_id = $ae_loc.site_cfg_json.slct__event_id;
} else if ($events_slct.event_id) {
// console.log(`Event ID already set:`, $events_slct.event_id);
$events_loc.event_id = $events_slct.event_id;
} else if ($ae_loc.default__event_id) {
$events_slct.event_id = $ae_loc.default__event_id;
$events_loc.event_id = $ae_loc.default__event_id;
} else {
console.log(`No Event ID set.`);
}
if ($ae_loc.site_cfg_json.slct__sponsorship_cfg_id) {
$slct.sponsorship_cfg_id = $ae_loc.site_cfg_json.slct__sponsorship_cfg_id;
$ae_loc.mod.sponsorships.cfg_id = $ae_loc.site_cfg_json.slct__sponsorship_cfg_id;
} else if ($ae_loc.default__sponsorship_cfg_id) {
$slct.sponsorship_cfg_id = $ae_loc.default__sponsorship_cfg_id;
$ae_loc.mod.sponsorships.cfg_id = $ae_loc.default__sponsorship_cfg_id;
} else {
console.log(`No Sponsorship Config ID set.`);
}
if (!$ae_loc.user_email) {
$ae_loc.user_email = 'test@oneskyit.com';
}
if (browser) {
// Waiting until the browser exists.
if ($ae_loc && $ae_sess && $ae_loc.ver_idb != $ae_sess.ver_idb) {
console.log('New version of the IDB available!!!');
console.log(`$ae_loc.ver_idb: ${$ae_loc.ver_idb} != $ae_sess.ver_idb: ${$ae_sess.ver_idb}`);
// Clear Indexed DB as well
indexedDB.deleteDatabase('ae_core_db');
indexedDB.deleteDatabase('ae_events_db');
$ae_loc.ver_idb = $ae_sess.ver_idb;
window.location.reload();
}
if ($ae_loc && $ae_sess && ($ae_loc.ver != $ae_sess.ver)) {
console.log('New version of the data store available!!!');
console.log(`$ae_loc.ver: ${$ae_loc.ver} != $ae_sess.ver: ${$ae_sess.ver}`);
// alert('New version available!!!');
$ae_loc.ver = $ae_sess.ver;
// $ae_loc = {};
localStorage.removeItem('ae_loc');
localStorage.removeItem('events_loc');
// localStorage.clear();
// sessionStorage.removeItem('ae_sess');
// sessionStorage.removeItem('events_sess');
// sessionStorage.clear();
// This does not seem to work fast enough or something?
// goto('/', {replaceState: true, invalidateAll: true});
// localStorage.removeItem('ae_loc');
// localStorage.removeItem('events_loc');
localStorage.clear();
sessionStorage.clear();
window.location.reload();
// localStorage.removeItem('ae_loc');
// localStorage.removeItem('events_loc');
// localStorage.clear();
}
// save_ds_to_local(ae_acct.ds);
let ae_ds = ae_acct.ds;
console.log(`ae_ds__ data:`, ae_ds)
for (let [key, value] of Object.entries(ae_ds)) {
console.log(`ae_ds__ key: ${key}, value:`, value);
localStorage.setItem(`ae_ds__${key}`, JSON.stringify(value));
// This should not be needed here anymore.
// if (key == 'hub__site__appshell_header') {
// $ae_sess.site_appshell_header = value;
// console.log(`$ae_sess.site_appshell_header = `, $ae_sess.site_appshell_header);
// }
}
// $ae_sess.site_appshell_header = JSON.parse(localStorage.getItem('ae_ds__hub__site__appshell_header'));
// console.log(`$ae_sess.site_appshell_header = `, $ae_sess.site_appshell_header);
}
// We want to loop through all of the data store (ds) key value pairs and set them to localStorage
// $: if (ae_acct.ds) {
// console.log(`ae_ds__ data:`, ae_acct.ds)
// for (let [key, value] of Object.entries(ae_acct.ds)) {
// console.log(`ae_ds__ key: ${key}, value:`, value);
// localStorageStore(`ae_ds__${key}`, value);
// }
// }
onMount(() => {
console.log('Root: +layout.svelte');
// Waiting until the browser exists.
// save_ds_to_local(ae_acct.ds);
// $ae_sess.site_appshell_header = JSON.parse(localStorage.getItem('ae_ds__hub__site__appshell_header'));
// console.log(`$ae_sess.site_appshell_header = `, $ae_sess.site_appshell_header);
// $ae_sess = $ae_sess;
let iframe = data.url.searchParams.get('iframe');
if (iframe == 'true') {
console.log('Use iframe layout!');
// data_struct['iframe'] = iframe;
$ae_loc.iframe = true;
document.getElementsByTagName('html')[0].classList.add('iframe');
document.getElementsByTagName('html')[0].classList.remove('dark');
document.getElementsByTagName('html')[0].classList.remove('light');
$ae_loc.hub.show_element__access_type = false;
$ae_loc.hub.show_element__cfg = false;
} else if (iframe == 'false') {
// data_struct['iframe'] = false;
$ae_loc.iframe = false;
document.getElementsByTagName('html')[0].classList.remove('iframe');
document.getElementsByTagName('html')[0].classList.add('light');
}
if (!$ae_loc.iframe && $ae_loc.trusted_access) {
$ae_loc.hub.show_element__access_type = true;
$ae_loc.hub.show_element__cfg = true;
} else if ($ae_loc.iframe && $ae_loc.manager_access) {
$ae_loc.hub.show_element__access_type = true;
$ae_loc.hub.show_element__cfg = true;
} else {
$ae_loc.hub.show_element__access_type = true;
$ae_loc.hub.show_element__cfg = false;
}
if (data.url.searchParams.get('event_id')) {
$events_slct.event_id = data.url.searchParams.get('event_id');
$events_loc.event_id = data.url.searchParams.get('event_id');
}
if (data.url.searchParams.get('sponsorship_cfg_id')) {
$slct.sponsorship_cfg_id = data.url.searchParams.get('sponsorship_cfg_id');
$ae_loc.mod.sponsorships.cfg_id = data.url.searchParams.get('sponsorship_cfg_id');
}
// TESTING TESTING TESTING
// WARNING: This needs to be tied to an object type and ID. This is a temporary solution.
// $ae_sess.download = {
// 'endpoint': '/event/file/abc123/download',
// 'filename': 'example.txt',
// 'size_total': 0,
// 'size_loaded': 0,
// 'percent_completed': 0,
// };
// This is how the download and upload progress is tracked.
window.addEventListener('message', function(event) {
if (log_lvl) {
console.log('Message received in root +layout.svelte:');
console.log(event);
}
if (event.data.type == 'api_download_blob') {
if (log_lvl) {
console.log('Download blob (file) message received:', event.data);
}
let task_id = event.data.task_id;
// $ae_sess.download[event.data.endpoint] = {
// 'status': event.data.status,
// 'task_id': task_id,
// 'endpoint': event.data.endpoint,
// 'filename': event.data.filename,
// 'size_total': event.data.size_total,
// 'size_loaded': event.data.size_loaded,
// 'percent_completed': event.data.percent_completed,
// };
$ae_sess.api_download_kv[task_id] =
{
'status': event.data.status,
'task_id': task_id,
'endpoint': event.data.endpoint,
'filename': event.data.filename,
'size_total': event.data.size_total,
'size_loaded': event.data.size_loaded,
'percent_completed': event.data.percent_completed,
};
} else if (event.data.type == 'api_post_json_form') {
if (log_lvl) {
console.log('Post JSON form message received:', event.data);
}
let task_id = event.data.task_id;
$ae_sess.api_upload_kv[task_id] =
{
'status': event.data.status,
'task_id': task_id,
'endpoint': event.data.endpoint,
'filename': event.data.filename,
'size_total': event.data.size_total,
'size_loaded': event.data.size_loaded,
'percent_completed': event.data.percent_completed,
'progress': event.data.progress,
'rate': event.data.rate,
};
}
});
});
</script>
<svelte:head>
<title>{$ae_loc.title ?? 'Æ loading...'}</title>
<link rel="stylesheet" href="{ae_acct.loc.site_style_href}">
<!-- <link rel="manifest" href="/manifest.json"> -->
</svelte:head>
<!-- regionFooter="flex justify-end space-x-2" -->
<Modal components={modalRegistry}
regionBackdrop=''
regionBody=''
regionHeader='modal-header card-header text-2xl font-bold'
regionFooter='modal-footer flex justify-between space-x-2'
/>
<!-- App Shell -->
<AppShell
regionPage={($ae_loc.iframe ? 'iframe' : '')}
slotHeader={($ae_loc.iframe ? 'iframe' : '')}
slotFooter={($ae_loc.iframe ? 'iframe' : '')}
>
<svelte:fragment slot="header">
<!-- App Bar -->
<AppBar
gridColumns="grid-cols-3"
slotDefault="place-self-center"
slotTrail="place-content-end"
padding="px-4"
>
<svelte:fragment slot="lead">
<Element_data_store
ds_code="hub__page__appshell_header_lead"
ds_type="html"
display="block"
/>
</svelte:fragment>
<!-- OSIT's Aether App -->
<!-- {@html (browser ? JSON.parse(localStorage.getItem('ae_ds__hub__site__appshell_header')).html : '-- not found --')} -->
<!-- {@html $ae_sess.site_appshell_header} -->
<Element_data_store
ds_code="hub__site__appshell_header"
ds_type="html"
display="block"
/>
<svelte:fragment slot="trail">
<Element_data_store
ds_code="hub__page__appshell_header_trail"
ds_type="html"
display="block"
/>
</svelte:fragment>
</AppBar>
<!-- <AppBar>
<svelte:fragment slot="lead">
<strong class="text-xl uppercase">Skeleton</strong>
</svelte:fragment>
<svelte:fragment slot="trail">
<a
class="btn btn-sm variant-ghost-surface"
href="https://discord.gg/EXqV7W8MtY"
target="_blank"
rel="noreferrer"
>
Discord
</a>
<a
class="btn btn-sm variant-ghost-surface"
href="https://twitter.com/SkeletonUI"
target="_blank"
rel="noreferrer"
>
Twitter
</a>
<a
class="btn btn-sm variant-ghost-surface"
href="https://github.com/skeletonlabs/skeleton"
target="_blank"
rel="noreferrer"
>
GitHub
</a>
</svelte:fragment>
</AppBar> -->
</svelte:fragment>
<!-- Page Route Content -->
<slot />
<svelte:fragment slot="footer">
<div
class="flex text-sm sm:text-sm md:text-md lg:text-md xl:text-md 2xl:text-lg text-slate-400 hover:text-slate-800 transition px-1"
class:ae_debug={$ae_loc.debug}
>
<Element_data_store
ds_code="hub__site__appshell_footer"
ds_type="html"
display="block"
class_li="grow flex flex-row justify-between"
/>
<button
on:click={() => {
console.log('Debug ae_loc:', $ae_loc);
$ae_loc.debug = !$ae_loc?.debug;
}}
id="AE-Quick-Debug"
class="ae_quick_debug btn btn-sm variant-glass-surface"
title="Turn debug content and styles off and on"
>
&pi;
</button>
</div>
</svelte:fragment>
</AppShell>
{#if $ae_loc.hub?.show_element__access_type}
<Element_access_type />
{/if}
<span
class:hidden={!$ae_loc?.hub?.show_element__cfg}
>
<!-- {#if $ae_loc?.hub?.show_element__cfg} -->
<Element_app_cfg set_theme_mode={true} set_theme_name={true} />
<!-- {/if} -->
</span>
<style lang="postcss">
/* BEGIN: AE's Svelte Quick Debug component */
#AE-Quick-Debug {
/* position: absolute; */
position: fixed;
/* position: relative; */
/* position: static; */
/* position: sticky; */
/* top: 1em; */
bottom: 0rem;
right: 0rem;
padding: .0rem;
/* lightyellow */
/* background-color: hsla(60,100%,90%,.30); */
/* background-color: rgba(var(--color-surface-500) / .5); */
border: none;
border-top: solid thin hsla(0,0%,0%,.25);
border-left: solid thin hsla(0,0%,0%,.25);
border-bottom: solid thin hsla(0,0%,0%,.25);
/* border-top-left-radius: .5em; */
/* border-bottom-left-radius: .5em; */
opacity: .15;
/* opacity: 1; */
font-size: .75rem;
z-index: 5;
/* NOTE: transition when no longer hovering */
transition-property: opacity, background-color;
transition-delay: 1.25s;
transition-duration: .5s;
transition-timing-function: ease-out;
}
#AE-Quick-Debug:hover {
/* lightyellow */
/* background-color: hsla(60,100%,90%,.95); */
/* background-color: rgba(var(--color-surface-500) / 1); */
border-top: solid thin hsla(0,0%,0%,.95);
border-left: solid thin hsla(0,0%,0%,.95);
border-bottom: solid thin hsla(0,0%,0%,.95);
opacity: 1;
padding: .5rem;
font-size: 1.75rem;
/* Need to zoom 3.5 when hovering */
/* transform: scale(3.5); */
/* NOTE: transition when hover starts */
transition-property: opacity, background-color;
transition-delay: .5s;
transition-duration: .10s;
transition-timing-function: ease-in;
}
</style>

219
src/routes/+layout.ts Normal file
View File

@@ -0,0 +1,219 @@
/** @type {import('./$types').LayoutLoad} */
// console.log(`ae_root +layout.ts: start`);
import { error } from '@sveltejs/kit';
// import { api } from '$lib/api';
// import { ae_loc, ae_sess, ae_api, slct, slct_trigger } from '$lib/ae_stores';
import { core_func } from '$lib/ae_core_functions';
import type { key_val } from '$lib/ae_stores';
import { PUBLIC_AE_API_PROTOCOL, PUBLIC_AE_API_SERVER, PUBLIC_AE_API_BAK_SERVER, PUBLIC_AE_API_PORT, PUBLIC_AE_API_PATH, PUBLIC_AE_API_SECRET_KEY, PUBLIC_AE_API_CRUD_SUPER_KEY, PUBLIC_AE_NO_ACCOUNT_ID, PUBLIC_AE_NO_ACCOUNT_ID_TOKEN } from '$env/static/public';
const api_base_url = `${PUBLIC_AE_API_PROTOCOL}://${PUBLIC_AE_API_SERVER}:${PUBLIC_AE_API_PORT}${PUBLIC_AE_API_PATH}`;
const api_base_url_bak = `${PUBLIC_AE_API_PROTOCOL}://${PUBLIC_AE_API_BAK_SERVER}:${PUBLIC_AE_API_PORT}${PUBLIC_AE_API_PATH}`;
const api_secret_key = PUBLIC_AE_API_SECRET_KEY;
const api_crud_super_key = PUBLIC_AE_API_CRUD_SUPER_KEY;
let ae_account_id: null|string = null;
const ae_no_account_id = PUBLIC_AE_NO_ACCOUNT_ID;
const ae_no_account_id_token = PUBLIC_AE_NO_ACCOUNT_ID_TOKEN;
let ae_api_init: key_val = {
'ver': '2024-08-11_11',
'base_url': api_base_url,
'base_url_bak': api_base_url_bak,
'api_secret_key': api_secret_key, // 'YOUR_API_SECRET_KEY',
'api_secret_key_bak': api_secret_key, // 'YOUR_API_SECRET_KEY',
'api_crud_super_key': api_crud_super_key, // 'YOUR_SUPER_KEY' 'zp5PtX4zUsI'
'headers': {},
'account_id': ae_account_id,
};
let ae_api_headers: key_val = {};
ae_api_headers['Access-Control-Allow-Origin'] = '*';
ae_api_headers['content-type'] = 'application/json';
ae_api_headers['x-aether-api-key'] = ae_api_init.api_secret_key;
ae_api_headers['x-aether-api-token'] = 'fake-temp-token';
ae_api_headers['x-aether-api-expire-on'] = '';
if (ae_account_id) {
ae_api_headers['x-account-id'] = ae_account_id;
} else {
// ae_api_headers['x-account-id'] = ;
}
if (ae_no_account_id) {
ae_api_headers['x-no-account-id'] = ae_no_account_id;
}
ae_api_init['headers'] = ae_api_headers;
let ae_loc_init: key_val = {
};
// export const prerender = false;
// There is not an initial data store from SvelteKit for this, so we will just use the API to get the data.
// properties: params, route, url
// functions: fetch, setHeaders, parent, depends, untrack
export async function load({ fetch, params, parent, route, url }) { // params, route, url
// console.log(`Svelte root layout.ts params:`, params);
// console.log(`Svelte root layout.ts route:`, route);
// console.log(`Svelte root layout.ts url:`, url);
let account_id: Promise<any>;
let ae_acct: key_val = {
api: ae_api_init,
ds: {},
loc: {
'account_id': '',
'site_id': '',
'site_domain_id': '',
'iframe': false,
},
sess: {},
slct: {},
}
// let ae_loc_tmp = get(ae_loc);
// console.log(`ae_loc = `, ae_loc_tmp);
// let ae_api_tmp = get(ae_api);
// console.log(`ae_api = `, ae_api_tmp);
let ds_code_li: null|key_val = {};
// if (ae_loc_tmp && ae_loc_tmp.ds) {
// ds_code_li = ae_loc_tmp.ds;
// }
// console.log(`ae_ ds_code_li = `, ds_code_li);
let ds_code: null|string = null;
let data_struct: key_val = {
// ae_acct should only be updated and referenced by the corresponding account_id.
account_id: null,
ae_acct: {
// '_XY7DXtc9MY': ae_acct,
},
ae_loc: {},
ae_api: ae_api_init,
ae_ds: {},
ae_hub: {}, // was ae_core
ae_m_sponsorships: {},
ae_m_events: {},
ae_m_events_speakers: {},
ae_slct: {},
iframe: false,
ae_root_layout_ts: true,
params: params,
url: url,
// Not really used yet
sections: [
{ slug: 'new', title: 'New Test' },
{ slug: 'manage', title: 'Manage Test' },
{ slug: 'test', title: 'Test Test' },
],
// Not really used yet
submenu: {},
};
// First do a site_domain look up to check if it is valid and get the account_id.
// ae_loc.url_host = data.url.host; // Use this to look up? sub.example.com:123
// ae_loc.fqdn = url.host; // Use this to look up? sub.example.com:123
// ae_loc.url_hostname = data.url.hostname; // sub.example.com
// ae_loc.url_origin = data.url.origin; // Use this to look up? https://sub.example.com:123
// ae_loc.site_domain = data.url.origin;
// console.log(`ae_loc = `, ae_loc);
account_id = await core_func.handle_load_ae_obj_id__site_domain({api_cfg: ae_api_init, fqdn: url.host, try_cache: false, log_lvl: 1})
.then(function (site_domain_results) {
if (site_domain_results) {
// console.log(`ae_ site_domain_results = `, site_domain_results);
data_struct.account_id = site_domain_results.account_id_random;
ae_acct.account_id = site_domain_results.account_id_random;
ae_api_init['account_id'] = site_domain_results.account_id_random;
ae_api_init['headers']['x-account-id'] = site_domain_results.account_id_random;
ae_api_init['headers']['x-no-account-id'] = null;
ae_loc_init['account_id'] = site_domain_results.account_id_random;
ae_loc_init['account_code'] = site_domain_results.account_code; // Useful for export file naming
ae_loc_init['account_name'] = site_domain_results.account_name; // Generally useful for display
ae_loc_init['site_id'] = site_domain_results.site_id_random;
ae_loc_init['site_domain_id'] = site_domain_results.site_domain_id_random;
ae_loc_init['site_enable'] = site_domain_results.enable;
ae_loc_init['site_header_image_path'] = site_domain_results.header_image_path;
ae_loc_init['site_style_href'] = site_domain_results.style_href;
ae_loc_init['site_google_tracking_id'] = site_domain_results.google_tracking_id;
ae_loc_init['site_cfg_json'] = site_domain_results.cfg_json;
console.log(`root layout.ts: Returning account_id = `, site_domain_results.account_id_random);
return site_domain_results.account_id_random;
}
console.log(`root layout.ts: Site domain results not found!!!`)
return null;
});
if (!account_id) {
console.log(`root layout.ts: The account_id was not found in API response!!!`);
// return false;
// return;
error(500, {
message: 'Account ID not found'
});
}
// console.log(ae_loc_init);
// NOTE: We need to wait for the account_id to be returned before we can continue. It is required for the api_cfg.
let ds_type: null|string = 'json';
ds_code = 'hub__page__access_code_li_json';
// console.log(`INFO: ae_ account_id = `, account_id);
// ae_acct['ds'][ds_code]
ds_code_li[ds_code] = await core_func.handle_load_ae_obj_code__data_store({api_cfg: ae_api_init, code: ds_code, data_type: ds_type, save_idb: false})
.then(function (ds_results) {
if (ds_results) {
console.log(`ae_ ds_results = `, ds_results);
return ds_results;
}
}
);
ae_loc_init['page_access_code_li'] = ds_code_li['hub__page__access_code_li_json'];
ae_acct['api'] = ae_api_init;
ae_acct['loc'] = ae_loc_init;
ae_acct['ds'] = ds_code_li;
ae_acct['slct'] = {
'account_id': account_id,
'site_domain_id': ae_loc_init.site_domain_id,
'site_id': ae_loc_init.site_id,
// For events_leads, events_badges, events_speakers
'event_id': ae_loc_init.site_cfg_json.slct__event_id,
'event_badge_template': ae_loc_init.site_cfg_json.slct__event_badge_template,
// For sponsorships
'sponsorship_cfg_id': ae_loc_init.site_cfg_json.slct__sponsorship_cfg_id,
}
// console.log(`ae_acct = `, ae_acct);
// WARNING: Precaution against shared data between sites and sessions.
// data_struct.ae_acct[ae_loc_init.account_id] = ae_acct;
data_struct[ae_loc_init.account_id] = ae_acct;
return data_struct;
}

View File

@@ -0,0 +1,11 @@
// export const ssr = false;
// export const prerender = true
// export const prerender = false;
// export const trailingSlash = 'always'; // 'never' | 'always' | 'ignore'
// import { TESTING } from '$env/static/private';
// console.log(`Aether Config - TESTING:`, TESTING);
// import { PRIVATE_TESTING } from '$env/static/private';
// console.log(`Aether Config - TESTING:`, PRIVATE_TESTING);

Some files were not shown because too many files have changed in this diff Show More