chore: remove orphaned legacy files and move QR scanner to elements/
- Trashed 10 unreferenced files: core .legacy types, bak files, element_modal_v1, element_websocket_v2, AE_MetadataFooter_not_ref, element_qr_scanner_v2 - Removed empty placeholder dirs: ae_db/, hooks/ - Moved element_qr_scanner_v3.svelte from lib root into elements/ - Updated 2 import paths for QR scanner (badges + leads) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,23 +0,0 @@
|
||||
export interface Account {
|
||||
id: string;
|
||||
// id_random: string;
|
||||
account_id: string;
|
||||
account_id_random: string;
|
||||
|
||||
code?: string;
|
||||
name: string;
|
||||
short_name?: null | string;
|
||||
description?: null | string;
|
||||
|
||||
enable: null | boolean;
|
||||
enable_from?: null | Date;
|
||||
enable_to?: null | Date;
|
||||
|
||||
hide?: null | boolean;
|
||||
priority?: null | boolean;
|
||||
sort?: null | number;
|
||||
group?: null | string;
|
||||
notes?: null | string;
|
||||
created_on: Date;
|
||||
updated_on?: null | Date;
|
||||
}
|
||||
@@ -1,736 +0,0 @@
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
import { api } from '$lib/api/api';
|
||||
|
||||
import { db_save_ae_obj_li__ae_obj } from '$lib/ae_core/core__idb_dexie';
|
||||
import { db_core } from '$lib/ae_core/db_core';
|
||||
|
||||
const ae_promises: key_val = {};
|
||||
|
||||
// Updated 2025-06-10
|
||||
export async function load_ae_obj_id__person({
|
||||
api_cfg,
|
||||
person_id,
|
||||
params = {},
|
||||
try_cache = false,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
person_id: string;
|
||||
params?: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_id__person() *** person_id=${person_id}`);
|
||||
}
|
||||
|
||||
ae_promises.load__person_obj = await api
|
||||
.get_ae_obj_id_crud({
|
||||
api_cfg: api_cfg,
|
||||
obj_type: 'person',
|
||||
obj_id: person_id,
|
||||
use_alt_table: false,
|
||||
use_alt_base: false,
|
||||
params: params,
|
||||
log_lvl: log_lvl
|
||||
})
|
||||
.then(async function (person_obj_get_result) {
|
||||
if (person_obj_get_result) {
|
||||
if (try_cache) {
|
||||
// Process the results first
|
||||
const processed_obj_li = await process_ae_obj__person_props({
|
||||
obj_li: [person_obj_get_result],
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
if (log_lvl) {
|
||||
console.log('Processed object list:', processed_obj_li);
|
||||
}
|
||||
// Save the updated results list to the database
|
||||
if (log_lvl) {
|
||||
console.log('Saving to DB...');
|
||||
}
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'person',
|
||||
obj_li: processed_obj_li,
|
||||
properties_to_save: properties_to_save,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
if (log_lvl) {
|
||||
console.log('DB save completed.');
|
||||
}
|
||||
|
||||
// // This is expecting a list
|
||||
// db_save_ae_obj_li__person({
|
||||
// obj_type: 'person',
|
||||
// obj_li: [person_obj_get_result],
|
||||
// log_lvl: log_lvl
|
||||
// });
|
||||
}
|
||||
return person_obj_get_result;
|
||||
} else {
|
||||
console.log('No results returned.');
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.catch(function (error: any) {
|
||||
console.log('No results returned or failed.', error);
|
||||
});
|
||||
|
||||
if (log_lvl) {
|
||||
console.log('ae_promises.load__person_obj:', ae_promises.load__person_obj);
|
||||
}
|
||||
|
||||
return ae_promises.load__person_obj;
|
||||
}
|
||||
|
||||
// Updated 2025-06-10
|
||||
export async function load_ae_obj_li__person({
|
||||
api_cfg,
|
||||
for_obj_type = 'account',
|
||||
for_obj_id,
|
||||
qry_email = null,
|
||||
qry_user_id = null,
|
||||
enabled = 'enabled',
|
||||
hidden = 'not_hidden',
|
||||
limit = 99,
|
||||
offset = 0,
|
||||
order_by_li = [
|
||||
{ family_name: 'ASC' },
|
||||
{ given_name: 'ASC' },
|
||||
{ updated_on: 'DESC' },
|
||||
{ created_on: 'DESC' }
|
||||
],
|
||||
// params_json = {},
|
||||
params = {},
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
for_obj_type: string;
|
||||
for_obj_id: string;
|
||||
qry_email?: string | null;
|
||||
qry_user_id?: string | null;
|
||||
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined; // all, disabled, enabled
|
||||
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined; // all, hidden, not_hidden
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
order_by_li?: { [key: string]: 'ASC' | 'DESC' }[] | null;
|
||||
// params_json?: null|key_val,
|
||||
params?: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`*** load_ae_obj_li__person() *** for_obj_type=${for_obj_type} for_obj_id=${for_obj_id} enabled=${enabled} hidden=${hidden} limit=${limit} offset=${offset}`
|
||||
);
|
||||
}
|
||||
|
||||
const params_json: key_val = {};
|
||||
|
||||
// console.log('params_json:', params_json);
|
||||
if (qry_user_id) {
|
||||
// params_json['and_qry'] = {};
|
||||
// params_json['and_qry']['user_id_random'] = qry_user_id;
|
||||
|
||||
params_json['qry'] = [];
|
||||
|
||||
const qry_param = {
|
||||
type: 'AND',
|
||||
field: 'user_id_random',
|
||||
operator: '=',
|
||||
value: qry_user_id
|
||||
};
|
||||
params_json['qry'].push(qry_param);
|
||||
}
|
||||
|
||||
if (log_lvl) {
|
||||
console.log('params_json:', params_json);
|
||||
}
|
||||
|
||||
ae_promises.load__person_obj_li = await api
|
||||
.get_ae_obj_li_for_obj_id_crud_v2({
|
||||
api_cfg: api_cfg,
|
||||
obj_type: 'person',
|
||||
for_obj_type: for_obj_type,
|
||||
for_obj_id: for_obj_id,
|
||||
use_alt_tbl: false,
|
||||
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(async function (person_obj_li_get_result) {
|
||||
if (person_obj_li_get_result) {
|
||||
if (try_cache) {
|
||||
// Process the results first
|
||||
const processed_obj_li = await process_ae_obj__person_props({
|
||||
obj_li: person_obj_li_get_result,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
if (log_lvl) {
|
||||
console.log('Processed object list:', processed_obj_li);
|
||||
}
|
||||
// Save the updated results list to the database
|
||||
if (log_lvl) {
|
||||
console.log('Saving to DB...');
|
||||
}
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'person',
|
||||
obj_li: processed_obj_li,
|
||||
properties_to_save: properties_to_save,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
if (log_lvl) {
|
||||
console.log('DB save completed.');
|
||||
}
|
||||
|
||||
// db_save_ae_obj_li__person({
|
||||
// obj_type: 'person',
|
||||
// obj_li: person_obj_li_get_result,
|
||||
// log_lvl: log_lvl
|
||||
// });
|
||||
}
|
||||
return person_obj_li_get_result;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
})
|
||||
.catch(function (error: any) {
|
||||
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 2025-06-10
|
||||
export async function create_ae_obj__person({
|
||||
api_cfg,
|
||||
user_id,
|
||||
data_kv,
|
||||
params = {},
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
user_id?: string;
|
||||
data_kv: key_val;
|
||||
params?: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** 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(async function (person_obj_create_result) {
|
||||
if (person_obj_create_result) {
|
||||
if (try_cache) {
|
||||
// Process the results first
|
||||
const processed_obj_li = await process_ae_obj__person_props({
|
||||
obj_li: [person_obj_create_result],
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
if (log_lvl) {
|
||||
console.log('Processed object list:', processed_obj_li);
|
||||
}
|
||||
// Save the updated results list to the database
|
||||
if (log_lvl) {
|
||||
console.log('Saving to DB...');
|
||||
}
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'person',
|
||||
obj_li: processed_obj_li,
|
||||
properties_to_save: properties_to_save,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
if (log_lvl) {
|
||||
console.log('DB save completed.');
|
||||
}
|
||||
|
||||
// db_save_ae_obj_li__person(
|
||||
// {
|
||||
// obj_type: 'person',
|
||||
// obj_li: [person_obj_create_result],
|
||||
// log_lvl: log_lvl
|
||||
// });
|
||||
}
|
||||
return person_obj_create_result;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.catch(function (error: any) {
|
||||
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 2025-05-10
|
||||
export async function delete_ae_obj_id__person({
|
||||
api_cfg,
|
||||
person_id,
|
||||
method = 'delete', // 'delete', 'disable', 'hide'
|
||||
params = {},
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
person_id: string;
|
||||
method?: string;
|
||||
params?: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** delete_ae_obj_id__person() *** person_id=${person_id}`);
|
||||
}
|
||||
|
||||
ae_promises.delete__person_obj = await api
|
||||
.delete_ae_obj_id_crud({
|
||||
api_cfg: api_cfg,
|
||||
obj_type: 'person',
|
||||
obj_id: person_id,
|
||||
key: api_cfg.api_crud_super_key,
|
||||
params: params,
|
||||
method: method,
|
||||
log_lvl: log_lvl
|
||||
})
|
||||
.catch(function (error: any) {
|
||||
console.log('No results returned or failed.', error);
|
||||
})
|
||||
.finally(async function () {
|
||||
if (try_cache) {
|
||||
if (log_lvl) {
|
||||
console.log(`Attempting to remove IDB entry for person_id=${person_id}`);
|
||||
}
|
||||
await db_core.person.delete(person_id);
|
||||
}
|
||||
});
|
||||
|
||||
if (log_lvl) {
|
||||
console.log('ae_promises.delete__person_obj:', ae_promises.delete__person_obj);
|
||||
}
|
||||
|
||||
return ae_promises.delete__person_obj;
|
||||
}
|
||||
|
||||
// Updated 2025-06-10
|
||||
export async function update_ae_obj__person({
|
||||
api_cfg,
|
||||
person_id,
|
||||
data_kv,
|
||||
params = {},
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
person_id: string;
|
||||
data_kv: key_val;
|
||||
params?: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** update_ae_obj__person() *** person_id=${person_id}`, data_kv);
|
||||
}
|
||||
|
||||
// log_lvl = 1;
|
||||
|
||||
// Perform the API update
|
||||
const result = await api.update_ae_obj_id_crud({
|
||||
api_cfg: api_cfg,
|
||||
obj_type: 'person',
|
||||
obj_id: person_id,
|
||||
fields: data_kv,
|
||||
key: api_cfg.api_crud_super_key,
|
||||
params: params,
|
||||
return_obj: true,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
|
||||
// Handle the result
|
||||
if (result) {
|
||||
if (try_cache) {
|
||||
// Process the results first
|
||||
const processed_obj_li = await process_ae_obj__person_props({
|
||||
obj_li: [result],
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
if (log_lvl) {
|
||||
console.log('Processed object list:', processed_obj_li);
|
||||
}
|
||||
// Save the updated results list to the database
|
||||
if (log_lvl) {
|
||||
console.log('Saving to DB...');
|
||||
}
|
||||
await db_save_ae_obj_li__ae_obj({
|
||||
db_instance: db_core,
|
||||
table_name: 'person',
|
||||
obj_li: processed_obj_li,
|
||||
properties_to_save: properties_to_save,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
if (log_lvl) {
|
||||
console.log('DB save completed.');
|
||||
}
|
||||
|
||||
// await db_save_ae_obj_li__person({
|
||||
// obj_type: 'person',
|
||||
// obj_li: [result],
|
||||
// log_lvl: log_lvl,
|
||||
// });
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
console.error('Failed to update person.');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Updated 2024-06-10
|
||||
export function 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(`*** 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);
|
||||
}
|
||||
|
||||
const obj_record = {
|
||||
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,
|
||||
full_name_override: obj.full_name_override, // was display_name and display_name_override
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
let id_random = null;
|
||||
|
||||
try {
|
||||
id_random = await db_core.person.update(obj_record.id, obj_record);
|
||||
} catch (error) {
|
||||
console.log(`Error: Failed to update ${obj_record.id}: ${error}`);
|
||||
}
|
||||
if (!id_random) {
|
||||
if (log_lvl) {
|
||||
console.log(`Failed to update record with ID: ${obj_record.id}. Trying put...`);
|
||||
}
|
||||
try {
|
||||
id_random = await db_core.person.put(obj_record);
|
||||
} catch (error) {
|
||||
console.log(`Error: Failed to put ${obj.person_id_random}: ${error}`);
|
||||
}
|
||||
} else {
|
||||
if (log_lvl) {
|
||||
console.log(`Updated record with ID: ${obj_record.id}`);
|
||||
}
|
||||
}
|
||||
if (!id_random) {
|
||||
console.log(`Failed to save record with ID: ${obj_record.id}`);
|
||||
} else {
|
||||
if (log_lvl) {
|
||||
console.log(`Saved record with ID: ${obj_record.id}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Updated 2025-06-10
|
||||
const properties_to_save = [
|
||||
'id',
|
||||
'person_id',
|
||||
// 'person_id_random',
|
||||
|
||||
'external_id',
|
||||
'external_sys_id',
|
||||
'code',
|
||||
|
||||
'account_id',
|
||||
// 'account_id_random',
|
||||
|
||||
'person_profile_id',
|
||||
// 'person_profile_id_random', // The new table person_profile will be used soon...
|
||||
|
||||
'user_id',
|
||||
// 'user_id_random',
|
||||
|
||||
'pronouns',
|
||||
'informal_name',
|
||||
'title_names',
|
||||
'given_name',
|
||||
'middle_name',
|
||||
'family_name',
|
||||
'designations',
|
||||
|
||||
'professional_title',
|
||||
|
||||
'full_name',
|
||||
'full_name_override', // was display_name and display_name_override
|
||||
|
||||
'affiliations',
|
||||
'primary_email',
|
||||
'biography',
|
||||
'agree',
|
||||
'comments',
|
||||
|
||||
'allow_auth_key', // For sign in without password
|
||||
// 'auth_key', // Should this be saved locally?
|
||||
'passcode',
|
||||
|
||||
// 'passcode_timeout',
|
||||
// 'passcode_read', // For LLM (AI) generated summary...???
|
||||
// 'passcode_read_expire',
|
||||
// 'passcode_write',
|
||||
// 'passcode_write_expire',
|
||||
// 'private_passcode',
|
||||
|
||||
// 'alert',
|
||||
// 'alert_msg',
|
||||
|
||||
'data_json',
|
||||
|
||||
'enable',
|
||||
'hide',
|
||||
'priority',
|
||||
'sort',
|
||||
'group',
|
||||
'notes',
|
||||
'created_on',
|
||||
'updated_on',
|
||||
|
||||
// Generated fields for sorting locally only
|
||||
'tmp_sort_1',
|
||||
'tmp_sort_2',
|
||||
'tmp_sort_3',
|
||||
|
||||
// From SQL view
|
||||
'username',
|
||||
// 'user_username', // Same as username
|
||||
'user_name',
|
||||
'user_email',
|
||||
'user_allow_auth_key', // For sign in without password
|
||||
'user_super',
|
||||
'user_manager',
|
||||
'user_administrator',
|
||||
'user_public',
|
||||
|
||||
'organization_id',
|
||||
// 'organization_id_random',
|
||||
'organization_name',
|
||||
|
||||
'contact_id',
|
||||
// 'contact_id_random',
|
||||
'contact_name',
|
||||
'contact_email',
|
||||
'contact_cc_email',
|
||||
'contact_phone_mobile',
|
||||
'contact_phone_home',
|
||||
'contact_phone_office',
|
||||
'contact_phone_land',
|
||||
'contact_phone_fax',
|
||||
'contact_phone_other',
|
||||
|
||||
'address_id',
|
||||
// 'address_id_random',
|
||||
'address_city',
|
||||
'address_country_alpha_2_code' // contact_address_country_alpha_2_code
|
||||
];
|
||||
|
||||
/**
|
||||
* NON-EXPORTED LOCAL HELPER
|
||||
* Processes a list of Aether objects by applying common and specific transformations.
|
||||
*/
|
||||
async function _process_generic_props<T extends Record<string, any>>({
|
||||
obj_li,
|
||||
obj_type,
|
||||
log_lvl = 0,
|
||||
specific_processor
|
||||
}: {
|
||||
obj_li: T[];
|
||||
obj_type: string;
|
||||
log_lvl?: number;
|
||||
specific_processor?: (obj: T) => Promise<T> | T;
|
||||
}): Promise<T[]> {
|
||||
if (log_lvl > 0) {
|
||||
console.log(
|
||||
`*** _process_generic_props: Processing ${obj_li.length} objects of type "${obj_type}" ***`
|
||||
);
|
||||
}
|
||||
|
||||
if (!obj_li || obj_li.length === 0) {
|
||||
if (log_lvl > 0) console.log('No objects to process.');
|
||||
return [];
|
||||
}
|
||||
|
||||
const processed_obj_li: T[] = [];
|
||||
|
||||
for (const original_obj of obj_li) {
|
||||
let processed_obj = { ...original_obj };
|
||||
|
||||
// --- Common Transformations ---
|
||||
|
||||
// 1. Standardize ID and other '_random' fields
|
||||
// The API often returns fields like 'person_id_random', which need to be aliased to 'person_id'.
|
||||
for (const key in processed_obj) {
|
||||
if (key.endsWith('_random')) {
|
||||
const new_key = key.slice(0, -7); // Remove '_random' suffix
|
||||
(processed_obj as any)[new_key] = processed_obj[key];
|
||||
}
|
||||
}
|
||||
// Ensure 'id' is set from '[obj_type]_id_random'
|
||||
const random_id_key = `${obj_type}_id_random`;
|
||||
if (processed_obj[random_id_key]) {
|
||||
(processed_obj as any).id = processed_obj[random_id_key];
|
||||
}
|
||||
|
||||
// 2. Create common computed properties for client-side sorting.
|
||||
const group = processed_obj.group ?? '0';
|
||||
const priority = processed_obj.priority ? 1 : 0;
|
||||
const sort = processed_obj.sort ?? '0';
|
||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||
const name = processed_obj.name ?? '';
|
||||
|
||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
||||
|
||||
// --- Specific Transformations ---
|
||||
if (specific_processor) {
|
||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
||||
}
|
||||
|
||||
processed_obj_li.push(processed_obj as T);
|
||||
}
|
||||
|
||||
return processed_obj_li;
|
||||
}
|
||||
|
||||
// Updated 2025-06-10
|
||||
export async function process_ae_obj__person_props({
|
||||
obj_li,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
obj_li: any[];
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
return _process_generic_props({
|
||||
obj_li,
|
||||
obj_type: 'person',
|
||||
log_lvl,
|
||||
specific_processor: (obj) => {
|
||||
// Person-specific computed sort fields, overriding generic ones if needed
|
||||
obj.tmp_sort_1 = `${obj.group ?? '0'}_${obj.priority ? 1 : 0}_${
|
||||
obj.sort ?? '0'
|
||||
}_${obj.updated_on}_${obj.created_on}`;
|
||||
obj.tmp_sort_2 = `${obj.group ?? '0'}_${obj.priority ? 1 : 0}_${
|
||||
obj.sort ?? '0'
|
||||
}_${obj.updated_on ?? obj.created_on}`;
|
||||
obj.tmp_sort_3 = `${obj.group ?? '0'}_${obj.priority ? 1 : 0}_${
|
||||
obj.sort ?? '0'
|
||||
}_${obj.name ?? ''}_${obj.updated_on ?? obj.created_on}`;
|
||||
|
||||
return obj;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
export interface Site {
|
||||
id: string;
|
||||
// id_random: string;
|
||||
site_id: string;
|
||||
site_id_random?: string;
|
||||
|
||||
code?: string;
|
||||
|
||||
account_id: string;
|
||||
account_id_random?: string;
|
||||
|
||||
name: string;
|
||||
description?: null | string;
|
||||
|
||||
restrict_access?: null | boolean;
|
||||
access_key?: null | string;
|
||||
access_code_kv_json?: null | string;
|
||||
|
||||
logo_path?: null | string;
|
||||
logo_bg_color?: null | string; // Not really used currently.
|
||||
// background_image_path?: null|string; // Legacy field
|
||||
// background_bg_color?: null|string; // Legacy field
|
||||
title?: null | string;
|
||||
|
||||
// header_html?: null|string; // Legacy field
|
||||
// header_css?: null|string; // Legacy field
|
||||
// header_image_path?: null|string; // Legacy field
|
||||
// header_image_bg_color?: null|string; // Legacy field
|
||||
// body_html?: null|string; // Legacy field
|
||||
tagline?: null | string;
|
||||
// site_header_h1?: null|string; // Legacy field
|
||||
// site_header_h2?: null|string; // Legacy field
|
||||
style_href?: null | string; // Legacy field
|
||||
// script_src?: null|string; // Legacy field
|
||||
google_tracking_id?: null | string;
|
||||
|
||||
cfg_json?: null | string; // key value config json
|
||||
|
||||
enable: null | boolean;
|
||||
enable_from?: null | Date;
|
||||
enable_to?: null | Date;
|
||||
|
||||
hide?: null | boolean;
|
||||
priority?: null | boolean;
|
||||
sort?: null | number;
|
||||
group?: null | string;
|
||||
notes?: null | string;
|
||||
created_on: Date;
|
||||
updated_on?: null | Date;
|
||||
}
|
||||
@@ -1,352 +0,0 @@
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
import { api } from '$lib/api/api';
|
||||
|
||||
import { db_core } from '$lib/ae_core/db_core';
|
||||
|
||||
/*
|
||||
* *** LEGACY AUTHENTICATION HEADER LOGIC ***
|
||||
*
|
||||
* The functions in this file interact with legacy Aether API authentication endpoints
|
||||
* (e.g., /user/authenticate, /user/lookup_email).
|
||||
*
|
||||
* Unlike V3 endpoints which handle context automatically or via standard headers,
|
||||
* these legacy endpoints have specific requirements:
|
||||
*
|
||||
* 1. They often require the `x-account-id` header to be explicitly set to the target
|
||||
* account ID to find the user within that specific account context.
|
||||
* 2. The standard API wrapper logic might strip `x-account-id` if `x-no-account-id`
|
||||
* is present (Bootstrap Paradox logic). We must explicitly remove `x-no-account-id`
|
||||
* and set `x-account-id` to ensure the request is routed correctly.
|
||||
* 3. Some endpoints accept `account_id` as a query parameter, while others (like email sending)
|
||||
* may crash (500 Error) if unexpected parameters are passed.
|
||||
*/
|
||||
|
||||
const ae_promises: key_val = {};
|
||||
|
||||
// Updated 2025-04-04
|
||||
// This function handles username/password authentication.
|
||||
// It explicitly sets the x-account-id header to ensure the user is looked up in the correct account.
|
||||
export async function auth_ae_obj__username_password({
|
||||
api_cfg,
|
||||
account_id,
|
||||
null_account_id = false,
|
||||
username,
|
||||
password,
|
||||
params = {},
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
account_id: string;
|
||||
null_account_id?: boolean;
|
||||
username: string;
|
||||
password: string;
|
||||
params?: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`*** auth_ae_obj__username_password() *** account_id=${account_id} username=${username} password=${password}`
|
||||
);
|
||||
}
|
||||
|
||||
const endpoint = '/user/authenticate';
|
||||
|
||||
// Prepare API config with correct headers to override global guest settings
|
||||
const use_api_cfg = { ...api_cfg, headers: { ...api_cfg.headers } };
|
||||
if (account_id) {
|
||||
use_api_cfg.headers['x-account-id'] = account_id;
|
||||
delete use_api_cfg.headers['x-no-account-id'];
|
||||
params['account_id'] = account_id;
|
||||
}
|
||||
|
||||
if (null_account_id) {
|
||||
params['null_account_id'] = true;
|
||||
}
|
||||
params['username'] = username; // Required
|
||||
params['password'] = password; // Required
|
||||
params['inc_jwt'] = true; // Request a JWT in the response
|
||||
if (log_lvl > 1) {
|
||||
console.log(`auth_ae_obj__username_password() - params:`, params);
|
||||
}
|
||||
|
||||
ae_promises.auth__username_password = await api
|
||||
.get_object({
|
||||
api_cfg: use_api_cfg,
|
||||
endpoint: endpoint,
|
||||
params: params,
|
||||
// data: {},
|
||||
log_lvl: log_lvl
|
||||
})
|
||||
.then(async function (user_obj_get_result) {
|
||||
if (user_obj_get_result) {
|
||||
// if (try_cache) {
|
||||
// // This is expecting a list
|
||||
// db_save_ae_obj_li__user({
|
||||
// obj_type: 'user',
|
||||
// obj_li: [user_obj_get_result],
|
||||
// log_lvl: log_lvl
|
||||
// });
|
||||
// }
|
||||
return user_obj_get_result;
|
||||
} else {
|
||||
console.log('No results returned.');
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.catch(function (error: any) {
|
||||
console.log('No results returned or failed.', error);
|
||||
});
|
||||
|
||||
if (log_lvl) {
|
||||
console.log('ae_promises.auth__username_password:', ae_promises.auth__username_password);
|
||||
}
|
||||
return ae_promises.auth__username_password;
|
||||
}
|
||||
|
||||
// Updated 2025-04-04
|
||||
// This function handles authentication using a User ID and a one-time auth key.
|
||||
export async function auth_ae_obj__user_id_user_auth_key({
|
||||
api_cfg,
|
||||
account_id,
|
||||
user_id,
|
||||
user_auth_key,
|
||||
params = {},
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
account_id: string;
|
||||
user_id: string;
|
||||
user_auth_key: string;
|
||||
params?: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`*** auth_ae_obj__user_id_user_auth_key() *** account_id=${account_id} user_id=${user_id}`
|
||||
);
|
||||
}
|
||||
|
||||
const endpoint = '/user/authenticate';
|
||||
|
||||
// Prepare API config with correct headers to override global guest settings
|
||||
const use_api_cfg = { ...api_cfg, headers: { ...api_cfg.headers } };
|
||||
if (account_id) {
|
||||
use_api_cfg.headers['x-account-id'] = account_id;
|
||||
delete use_api_cfg.headers['x-no-account-id'];
|
||||
params['account_id'] = account_id;
|
||||
}
|
||||
|
||||
params['user_id'] = user_id; // Required
|
||||
params['auth_key'] = user_auth_key; // Required
|
||||
params['inc_jwt'] = true; // Request a JWT in the response
|
||||
if (log_lvl > 1) {
|
||||
console.log(`auth_ae_obj__user_id_user_auth_key() - params:`, params);
|
||||
}
|
||||
|
||||
ae_promises.auth__user_id_user_key = await api
|
||||
.get_object({
|
||||
api_cfg: use_api_cfg,
|
||||
endpoint: endpoint,
|
||||
params: params,
|
||||
log_lvl: log_lvl
|
||||
})
|
||||
.then(async function (user_obj_get_result) {
|
||||
if (user_obj_get_result) {
|
||||
return user_obj_get_result;
|
||||
} else {
|
||||
console.log('No results returned.');
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.catch(function (error: any) {
|
||||
console.log('No results returned or failed.', error);
|
||||
});
|
||||
|
||||
if (log_lvl) {
|
||||
console.log('ae_promises.auth__user_id_user_key:', ae_promises.auth__user_id_user_key);
|
||||
}
|
||||
return ae_promises.auth__user_id_user_key;
|
||||
}
|
||||
|
||||
// Send an email to the user with a new one time use authentication key. The new key must be generated and returned first.
|
||||
// Updated 2025-04-08
|
||||
// NOTE: This legacy endpoint is sensitive to extra query parameters and will 500 if account_id is passed in the URL.
|
||||
export async function send_email_auth_ae_obj__user_id({
|
||||
api_cfg,
|
||||
account_id,
|
||||
user_id,
|
||||
base_url,
|
||||
key_param_name = 'user_key', // API defaults to 'auth_key'
|
||||
params = {},
|
||||
// try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
account_id: string;
|
||||
user_id: string;
|
||||
base_url?: string;
|
||||
key_param_name?: string;
|
||||
params?: key_val;
|
||||
// try_cache?: boolean,
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`*** send_email_auth_ae_obj__user_id() *** account_id=${account_id} user_id=${user_id}`
|
||||
);
|
||||
}
|
||||
if (log_lvl > 1) {
|
||||
console.log(api_cfg);
|
||||
}
|
||||
|
||||
const email_auth_key_endpoint = `/user/${user_id}/email_auth_key_url`;
|
||||
params = {
|
||||
root_url: base_url,
|
||||
key_param_name: key_param_name
|
||||
};
|
||||
|
||||
// Prepare API config with correct headers to override global guest settings
|
||||
const use_api_cfg = { ...api_cfg, headers: { ...api_cfg.headers } };
|
||||
if (account_id) {
|
||||
use_api_cfg.headers['x-account-id'] = account_id;
|
||||
delete use_api_cfg.headers['x-no-account-id'];
|
||||
// WARNING: Do NOT add account_id to params here, as it causes a 500 error on the legacy backend.
|
||||
}
|
||||
|
||||
ae_promises.auth_key__send_email = await api.get_object({
|
||||
api_cfg: use_api_cfg,
|
||||
endpoint: email_auth_key_endpoint,
|
||||
params: params,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
|
||||
return ae_promises.auth_key__send_email;
|
||||
}
|
||||
|
||||
// Look up user based on email address provided
|
||||
// Updated 2025-04-08
|
||||
export async function qry_ae_obj_li__user_email({
|
||||
api_cfg,
|
||||
account_id,
|
||||
null_account_id = false,
|
||||
email,
|
||||
params = {},
|
||||
try_cache = true,
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
account_id: string;
|
||||
null_account_id?: boolean;
|
||||
email: string;
|
||||
params?: key_val;
|
||||
try_cache?: boolean;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(`*** qry_ae_obj_li__user_email() *** account_id=${account_id} email=${email}`);
|
||||
}
|
||||
|
||||
const endpoint = '/user/lookup_email';
|
||||
|
||||
// Prepare API config with correct headers to override global guest settings
|
||||
const use_api_cfg = { ...api_cfg, headers: { ...api_cfg.headers } };
|
||||
if (account_id) {
|
||||
use_api_cfg.headers['x-account-id'] = account_id;
|
||||
delete use_api_cfg.headers['x-no-account-id'];
|
||||
params['account_id'] = account_id;
|
||||
}
|
||||
|
||||
params['email'] = email; // Required
|
||||
params['null_account_id'] = null_account_id || false;
|
||||
|
||||
if (log_lvl > 1) {
|
||||
console.log(`qry_ae_obj_li__user_email() - params:`, params);
|
||||
}
|
||||
|
||||
ae_promises.qry__user_email = await api
|
||||
.get_object({
|
||||
api_cfg: use_api_cfg,
|
||||
endpoint: endpoint,
|
||||
params: params,
|
||||
log_lvl: log_lvl
|
||||
})
|
||||
.then(async function (user_obj_get_result) {
|
||||
if (user_obj_get_result) {
|
||||
return user_obj_get_result;
|
||||
} else {
|
||||
console.log('No results returned.');
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.catch(function (error: any) {
|
||||
console.log('No results returned or failed.', error);
|
||||
});
|
||||
|
||||
if (log_lvl) {
|
||||
console.log('ae_promises.qry__user_email:', ae_promises.qry__user_email);
|
||||
}
|
||||
return ae_promises.qry__user_email;
|
||||
}
|
||||
|
||||
// Change user password
|
||||
// endpoint: PATCH /user/{user_id}/change_password
|
||||
// params:
|
||||
// data_kv: password (the new password)
|
||||
// Updated 2025-04-11
|
||||
export async function auth_ae_obj__user_id_change_password({
|
||||
api_cfg,
|
||||
account_id,
|
||||
user_id,
|
||||
password,
|
||||
params = {},
|
||||
log_lvl = 0
|
||||
}: {
|
||||
api_cfg: any;
|
||||
account_id: string;
|
||||
user_id: string;
|
||||
password: string;
|
||||
params?: key_val;
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`*** auth_ae_obj__user_id_change_password() *** account_id=${account_id} user_id=${user_id}`
|
||||
);
|
||||
}
|
||||
|
||||
const endpoint = `/user/${user_id}/change_password`;
|
||||
|
||||
params['user_id'] = user_id; // Required
|
||||
if (log_lvl > 1) {
|
||||
console.log(`auth_ae_obj__user_id_change_password() - params:`, params);
|
||||
}
|
||||
|
||||
ae_promises.change_password__user_id = await api
|
||||
.patch_object({
|
||||
api_cfg: api_cfg,
|
||||
endpoint: endpoint,
|
||||
params: params,
|
||||
data: { password: password },
|
||||
log_lvl: log_lvl
|
||||
})
|
||||
.then(async function (change_password_result) {
|
||||
if (change_password_result) {
|
||||
return change_password_result;
|
||||
} else {
|
||||
console.log('No results returned.');
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.catch(function (error: any) {
|
||||
console.log('No results returned or failed.', error);
|
||||
});
|
||||
|
||||
if (log_lvl) {
|
||||
console.log('ae_promises.change_password__user_id:', ae_promises.change_password__user_id);
|
||||
}
|
||||
return ae_promises.change_password__user_id;
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
<script lang="ts">
|
||||
/**
|
||||
* AE_MetadataFooter.svelte
|
||||
* GENERIC Aether Metadata Display
|
||||
* Reusable across all modules to standardize created/updated/original info.
|
||||
*/
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import { ae_loc } from '$lib/stores/ae_stores';
|
||||
import { Clock, CalendarClock, Globe } from '@lucide/svelte';
|
||||
|
||||
interface Props {
|
||||
obj: any;
|
||||
showOriginal?: boolean;
|
||||
containerClass?: string;
|
||||
}
|
||||
|
||||
let {
|
||||
obj,
|
||||
showOriginal = true,
|
||||
containerClass = "ae_meta flex flex-col gap-2 p-4 border-t border-surface-500/10 text-xs text-surface-500 w-full"
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
<footer class={containerClass}>
|
||||
<!-- Original Date/Time Info (if applicable) -->
|
||||
{#if showOriginal && (obj?.original_datetime || obj?.original_timezone)}
|
||||
<div class="flex flex-row flex-wrap gap-x-4 gap-y-1 items-center bg-surface-500/5 p-2 rounded">
|
||||
<span class="flex items-center gap-1">
|
||||
<Globe size="1.1em" class="opacity-70" />
|
||||
<span class="font-bold uppercase tracking-tighter">Original:</span>
|
||||
{obj?.original_datetime ? ae_util.iso_datetime_formatter(obj.original_datetime, 'datetime_iso_12_no_seconds') : '--'}
|
||||
</span>
|
||||
{#if obj?.original_timezone}
|
||||
<span class="flex items-center gap-1">
|
||||
<span class="font-bold uppercase tracking-tighter">TZ:</span>
|
||||
{obj.original_timezone}
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- System Timestamps -->
|
||||
<div class="flex flex-col sm:flex-row justify-between items-center gap-2 px-1">
|
||||
<div class="flex flex-wrap gap-4 justify-center sm:justify-start">
|
||||
<span class="flex items-center gap-1" title="Creation date">
|
||||
<CalendarClock size="1.1em" class="opacity-70 text-primary-500" />
|
||||
<span class="font-semibold uppercase tracking-tighter">Created:</span>
|
||||
{ae_util.iso_datetime_formatter(obj?.created_on, 'datetime_iso_12_no_seconds')}
|
||||
</span>
|
||||
{#if obj?.updated_on}
|
||||
<span class="flex items-center gap-1" title="Last update">
|
||||
<Clock size="1.1em" class="opacity-70 text-secondary-500" />
|
||||
<span class="font-semibold uppercase tracking-tighter">Updated:</span>
|
||||
{ae_util.iso_datetime_formatter(obj.updated_on, 'datetime_iso_12_no_seconds')}
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if obj?.journal_entry_type || obj?.type}
|
||||
<span class="badge variant-soft-surface text-[10px] uppercase font-bold tracking-widest">
|
||||
Type: {obj?.journal_entry_type || obj?.type}
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
</footer>
|
||||
@@ -1,591 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { run, preventDefault } from 'svelte/legacy';
|
||||
|
||||
// *** Import Svelte core
|
||||
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
|
||||
// import 'html5-qrcode';
|
||||
import {
|
||||
Html5Qrcode,
|
||||
Html5QrcodeSupportedFormats
|
||||
} from 'html5-qrcode';
|
||||
|
||||
// *** Import Lucide icons
|
||||
import { Camera, Crosshair, Keyboard, QrCode, Send } from '@lucide/svelte';
|
||||
|
||||
// *** Import Aether core variables and functions
|
||||
import { api } from '$lib/api/api';
|
||||
import { ae_api } from '$lib/stores/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
|
||||
|
||||
interface Props {
|
||||
// *** Export/Exposed variables and functions for component
|
||||
start_qr_scanner?: boolean;
|
||||
show_pause_btn?: boolean; // pause and resume buttons
|
||||
show_qr_manual_text_entry_option?: boolean;
|
||||
show_qr_manual_badge_id_entry_option?: boolean;
|
||||
show_qr_scan_result?: boolean;
|
||||
qr_fps?: number;
|
||||
qr_viewfinder_width?: number; // 275 seems good... Need to not let the this be larger than the container which changes based on the width of the screen/window.
|
||||
qr_facing_mode?: string; // environment, user, { exact: 'environment'}, { exact: 'user'}
|
||||
}
|
||||
|
||||
let {
|
||||
start_qr_scanner = $bindable(true),
|
||||
show_pause_btn = false,
|
||||
show_qr_manual_text_entry_option = false,
|
||||
show_qr_manual_badge_id_entry_option = false,
|
||||
show_qr_scan_result = true,
|
||||
qr_fps = 10,
|
||||
qr_viewfinder_width = 275,
|
||||
qr_facing_mode = 'environment'
|
||||
}: Props = $props();
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
// *** Set initial variables
|
||||
let scanning_status: string = $state('not_started');
|
||||
let qr_scan_result: null | string = $state(null);
|
||||
let qr_found_text: null | string = null;
|
||||
let qr_entered_text: null | string = $state(null);
|
||||
let qr_entered_badge_id: null | string = $state(null);
|
||||
let show_qr_manual_entry: null | boolean = $state(null);
|
||||
let disable_submit_badge_id_btn: boolean = $state(true);
|
||||
|
||||
let search_query_str = $state('');
|
||||
|
||||
function handle_oninput_search_query_str(e: Event) {
|
||||
search_query_str = (e.target as HTMLInputElement).value;
|
||||
}
|
||||
|
||||
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 = $derived({ 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],
|
||||
verbose: false
|
||||
});
|
||||
}
|
||||
|
||||
// html5_qr_code = new Html5Qrcode(
|
||||
// 'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] }
|
||||
// );
|
||||
|
||||
debug_info = 'new Html5Qrcode for element id=qr_scanner_viewfinder';
|
||||
|
||||
// Intentional comparison used to disable this block during development/testing
|
||||
if (start_qr_scanner && (1 as any) == 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: any) => {
|
||||
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: string, decoded_result: any) {
|
||||
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: string, qr_code_error: any) {
|
||||
// console.log('*** handle_qr_scan_error() ***');
|
||||
|
||||
if (qr_code_error.type) {
|
||||
console.log(`Error scanning code = ${qr_error_message}`, qr_code_error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
run(() => {
|
||||
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: string, message: any) {
|
||||
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"
|
||||
onclick={() => {
|
||||
navigator.mediaDevices
|
||||
.getUserMedia({ video: true })
|
||||
.then(get_user_media_success, get_user_media_error);
|
||||
}}
|
||||
class="ae_btn__allow_camera btn btn-sm preset-tonal-primary"
|
||||
>
|
||||
<Camera size="1em" class="mx-1 inline-block" />
|
||||
Allow Camera Access
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
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 preset-tonal-primary"
|
||||
>
|
||||
<QrCode size="1em" class="mx-1 inline-block" />
|
||||
Start Scanning
|
||||
</button>
|
||||
|
||||
<!-- <button
|
||||
on:click={ () => {
|
||||
html5_qr_code.start({ facingMode: { exact: "environment"} }, config, qrCodeSuccessCallback);
|
||||
}}
|
||||
class="ae_btn__resume btn btn-sm preset-tonal-primary">
|
||||
<span class="fas fa-play"></span>
|
||||
Resume
|
||||
</button> -->
|
||||
|
||||
{#if scanning_status == 'scanning'}
|
||||
<button
|
||||
onclick={handle_stop_qr_scanning}
|
||||
class="ae_btn__stop btn btn-sm preset-tonal-secondary"
|
||||
>
|
||||
<Crosshair size="1em" class="animate-spin opacity-50 m-1" />
|
||||
<!-- <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 onclick={handle_qr_manual_entry} class="btn btn-md preset-tonal-warning"
|
||||
><Send size="1em" class="inline-block" /> Submit Text</button
|
||||
>
|
||||
|
||||
<div class="search_by_text">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Name or Email"
|
||||
aria-label="Name or Email"
|
||||
value={search_query_str}
|
||||
oninput={handle_oninput_search_query_str}
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
<button
|
||||
onclick={() => {
|
||||
handle_stop_qr_scanning();
|
||||
show_qr_manual_entry = true;
|
||||
}}
|
||||
class="btn btn-md preset-tonal-warning m-1"
|
||||
>
|
||||
<Keyboard size="1em" class="mx-1 inline-block" /> 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 onsubmit={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"
|
||||
onclick={handle_qr_manual_entry}
|
||||
disabled={disable_submit_badge_id_btn}
|
||||
class="btn btn-md preset-tonal-primary border border-primary-500 m-1"
|
||||
class:btn_default={disable_submit_badge_id_btn}
|
||||
class:btn_primary={!disable_submit_badge_id_btn}
|
||||
>
|
||||
<Send size="1em" class="mx-1 inline-block" /> Submit Badge ID
|
||||
</button>
|
||||
</form>
|
||||
{:else}
|
||||
<button
|
||||
onclick={() => {
|
||||
handle_stop_qr_scanning();
|
||||
show_qr_manual_entry = true;
|
||||
}}
|
||||
class="btn btn-md preset-tonal-secondary m-1"
|
||||
>
|
||||
<Keyboard size="1em" class="mx-1 inline-block" /> 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;
|
||||
}
|
||||
|
||||
.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>
|
||||
@@ -1,205 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
|
||||
interface Props {
|
||||
open?: boolean;
|
||||
title?: string;
|
||||
autoclose?: boolean;
|
||||
size?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | '7xl';
|
||||
placement?: 'top-center' | 'center' | 'bottom-center';
|
||||
class_li?: string; // Additional classes for the dialog
|
||||
header?: import('svelte').Snippet;
|
||||
children?: import('svelte').Snippet;
|
||||
footer?: import('svelte').Snippet;
|
||||
}
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
title = '',
|
||||
autoclose = true,
|
||||
size = 'md',
|
||||
placement = 'center',
|
||||
class_li = '',
|
||||
header,
|
||||
children,
|
||||
footer
|
||||
}: Props = $props();
|
||||
|
||||
let dialog_element: HTMLDialogElement;
|
||||
|
||||
// Open/close dialog reactively
|
||||
$effect(() => {
|
||||
if (dialog_element) {
|
||||
if (open) {
|
||||
dialog_element.showModal();
|
||||
} else {
|
||||
dialog_element.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
// Handle backdrop click to close (if autoclose is true)
|
||||
dialog_element.addEventListener('click', (event) => {
|
||||
if (autoclose && event.target === dialog_element) {
|
||||
open = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Handle Escape key to close
|
||||
const handle_keydown = (event: KeyboardEvent) => {
|
||||
if (event.key === 'Escape' && open) {
|
||||
event.preventDefault(); // Prevent default browser escape behavior (e.g., page back)
|
||||
open = false;
|
||||
}
|
||||
};
|
||||
window.addEventListener('keydown', handle_keydown);
|
||||
|
||||
onDestroy(() => {
|
||||
window.removeEventListener('keydown', handle_keydown);
|
||||
});
|
||||
});
|
||||
|
||||
// Determine max-width based on size prop
|
||||
let max_width_class = $derived(
|
||||
size === 'sm'
|
||||
? 'max-w-sm'
|
||||
: size === 'md'
|
||||
? 'max-w-md'
|
||||
: size === 'lg'
|
||||
? 'max-w-lg'
|
||||
: size === 'xl'
|
||||
? 'max-w-xl'
|
||||
: size === '2xl'
|
||||
? 'max-w-2xl'
|
||||
: size === '3xl'
|
||||
? 'max-w-3xl'
|
||||
: size === '4xl'
|
||||
? 'max-w-4xl'
|
||||
: size === '5xl'
|
||||
? 'max-w-5xl'
|
||||
: size === '6xl'
|
||||
? 'max-w-6xl'
|
||||
: size === '7xl'
|
||||
? 'max-w-7xl'
|
||||
: 'max-w-md'
|
||||
);
|
||||
|
||||
// Determine placement classes
|
||||
let placement_class = $derived(
|
||||
placement === 'top-center'
|
||||
? 'justify-center items-start pt-[5vh]'
|
||||
: placement === 'center'
|
||||
? 'justify-center items-center'
|
||||
: placement === 'bottom-center'
|
||||
? 'justify-center items-end pb-[5vh]'
|
||||
: 'justify-center items-center' // Default to center
|
||||
);
|
||||
</script>
|
||||
|
||||
<dialog
|
||||
bind:this={dialog_element}
|
||||
class="
|
||||
p-0 bg-transparent overflow-visible
|
||||
backdrop:bg-black/50 backdrop:backdrop-blur-sm
|
||||
"
|
||||
onclose={() => (open = false)}
|
||||
>
|
||||
<div
|
||||
class="
|
||||
bg-white dark:bg-gray-800 text-gray-800 dark:text-gray-200 rounded-lg shadow-xl
|
||||
flex flex-col
|
||||
mx-auto
|
||||
{max_width_class}
|
||||
w-full
|
||||
{class_li}
|
||||
"
|
||||
>
|
||||
<!-- Modal Header -->
|
||||
{#if title || header}
|
||||
<header
|
||||
class="flex items-center justify-between border-b border-gray-200 p-4 dark:border-gray-700"
|
||||
>
|
||||
{#if header}
|
||||
{@render header()}
|
||||
{:else}
|
||||
<h3 class="text-xl font-semibold">{title}</h3>
|
||||
{/if}
|
||||
<button
|
||||
onclick={() => (open = false)}
|
||||
class="rounded-full p-1 hover:bg-gray-200 dark:hover:bg-gray-700"
|
||||
title="Close modal"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</header>
|
||||
{/if}
|
||||
|
||||
<!-- Modal Body -->
|
||||
<main class="max-h-[70vh] overflow-y-auto p-4">
|
||||
{#if children}
|
||||
{@render children()}
|
||||
{/if}
|
||||
</main>
|
||||
|
||||
<!-- Modal Footer -->
|
||||
{#if footer}
|
||||
<footer class="border-t border-gray-200 p-4 dark:border-gray-700">
|
||||
{@render footer()}
|
||||
</footer>
|
||||
{/if}
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<style lang="postcss">
|
||||
dialog {
|
||||
display: flex; /* Override default to allow flexbox positioning */
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
dialog[open] {
|
||||
opacity: 0;
|
||||
animation: fade-in 0.15s forwards ease-out;
|
||||
}
|
||||
|
||||
dialog:not([open]) {
|
||||
opacity: 1;
|
||||
animation: fade-out 0.15s forwards ease-out;
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-out {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
pointer-events: none; /* Disable interaction while fading out */
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
/**
|
||||
* src/lib/element_qr_scanner_v3.svelte
|
||||
* src/lib/elements/element_qr_scanner_v3.svelte
|
||||
* QR Scanner v3 — Svelte 5 runes, auto-starts, no manual permission step.
|
||||
*
|
||||
* html5-qrcode's .start() handles camera permission internally.
|
||||
@@ -1,597 +0,0 @@
|
||||
<script lang="ts">
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
ws_connect?: boolean; // If true then we should be trying to connect to the WS server.
|
||||
ws_connect_status?: null | string;
|
||||
ws_server?: string;
|
||||
ws_retry_delay?: number;
|
||||
ws_retry_count?: number;
|
||||
base_url?: any;
|
||||
group_id?: string;
|
||||
client_id?: any;
|
||||
cmd?: null | string;
|
||||
msg?: null | string;
|
||||
type?: null | string; // msg, cmd, json, hello, bye
|
||||
trigger_send?: any;
|
||||
trigger_connect?: boolean;
|
||||
trigger_disconnect?: boolean;
|
||||
classes?: string;
|
||||
hide__ws_element?: boolean;
|
||||
hide__ws_form?: boolean;
|
||||
hide__ws_messages?: boolean;
|
||||
hide__ws_commands?: boolean;
|
||||
|
||||
ws_conn_status?: any;
|
||||
ws_recv_status?: any;
|
||||
ws_sent_status?: any;
|
||||
}
|
||||
|
||||
let {
|
||||
log_lvl = 0,
|
||||
ws_connect = $bindable(false),
|
||||
ws_connect_status = $bindable(null),
|
||||
ws_server = 'dev-api.oneskyit.com',
|
||||
ws_retry_delay = 3500,
|
||||
ws_retry_count = 0,
|
||||
base_url = `wss://${ws_server}/ws`,
|
||||
group_id = $bindable('ae-grp-99'),
|
||||
client_id = $bindable(Date.now()),
|
||||
cmd = $bindable(null),
|
||||
msg = $bindable(null),
|
||||
type = null,
|
||||
trigger_send = $bindable(null),
|
||||
trigger_connect = $bindable(false),
|
||||
trigger_disconnect = $bindable(false),
|
||||
classes = 'container p-1 bg-pink-100 text-xs mx-auto pb-16 mb-20 sm:mb-12 md:mb-8',
|
||||
hide__ws_element = $bindable(false),
|
||||
hide__ws_form = $bindable(true),
|
||||
hide__ws_messages = $bindable(false),
|
||||
hide__ws_commands = $bindable(false),
|
||||
|
||||
ws_conn_status = $bindable(null),
|
||||
ws_recv_status = $bindable(null),
|
||||
ws_sent_status = $bindable(null)
|
||||
}: Props = $props();
|
||||
|
||||
// import { run, prevent_default } from 'svelte/legacy';
|
||||
// import { createEventDispatcher, onMount } from 'svelte';
|
||||
|
||||
// *** Set initial variables
|
||||
// const dispatch = createEventDispatcher();
|
||||
|
||||
// JSON formatted data
|
||||
let ws_data: {
|
||||
client_id: string | null;
|
||||
target: string;
|
||||
type: string;
|
||||
msg: string | null;
|
||||
cmd: string | null;
|
||||
} = $state({
|
||||
client_id: null, // The device or browser ID if available.
|
||||
// 'src': null, // Sending client
|
||||
// 'account_id': null, // Essentially the person ID or user ID if available.
|
||||
// 'dest': null, // Destination client
|
||||
target: 'echo', // echo, dm (direct), grp (group), all (broadcast)
|
||||
type: 'cmd', // msg, cmd, json, hello, bye
|
||||
// 'grp': null, // Destination group
|
||||
msg: null, // Message string
|
||||
cmd: null // Command string
|
||||
// 'data': null,
|
||||
// 'b64': null,
|
||||
});
|
||||
|
||||
let ws_received_list_cmd: any[] = $state([]);
|
||||
let ws_received_list_other: any[] = $state([]);
|
||||
let ws_received_list_msg: string[] = [];
|
||||
|
||||
// onMount(async () => {
|
||||
// console.log('** Component Mounted: ** Element Websocket v2');
|
||||
// });
|
||||
|
||||
// *** Functions and Logic
|
||||
|
||||
function ws_connect_group_id({ group_id, client_id }: { group_id: string, client_id: any }) {
|
||||
if (!group_id) {
|
||||
group_id = 'ae-grp-99';
|
||||
console.log(
|
||||
`WS: No group_id specified! Setting to default: ${group_id}`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (!client_id) {
|
||||
client_id = Date.now();
|
||||
console.log(
|
||||
`WS: No client_id specified! Setting to current timestamp: ${client_id}`
|
||||
);
|
||||
// return false;
|
||||
}
|
||||
console.log(
|
||||
`WS Connect URL: ${base_url}/group/${group_id}/client/${client_id}`
|
||||
);
|
||||
let ws_connection = new WebSocket(
|
||||
`${base_url}/group/${group_id}/client/${client_id}`
|
||||
);
|
||||
|
||||
ws_connection.onopen = function () {
|
||||
console.log('WS: connected');
|
||||
|
||||
ws_connect_status = 'connected';
|
||||
|
||||
// dispatch('ws_conn', {
|
||||
// 'status': 'connected'
|
||||
// });
|
||||
ws_conn_status = 'connected';
|
||||
|
||||
ws_retry_count = 0;
|
||||
|
||||
// ws_connection.send(JSON.stringify({
|
||||
// client_id: client_id,
|
||||
// target: 'echo',
|
||||
// type: 'hello',
|
||||
// group_id: group_id,
|
||||
// msg: 'You are connected!'
|
||||
// }));
|
||||
|
||||
ws_connection.send(
|
||||
JSON.stringify({
|
||||
client_id: client_id,
|
||||
target: 'all',
|
||||
type: 'hello',
|
||||
group_id: group_id,
|
||||
msg: `Client ${client_id.toString().slice(-5)} connected!`
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
ws_connection.onmessage = function (event) {
|
||||
if (log_lvl) {
|
||||
console.log('WS: message received', event);
|
||||
}
|
||||
|
||||
let ws_recv_data = JSON.parse(event.data);
|
||||
if (log_lvl) {
|
||||
console.log('WS: Received data:', ws_recv_data);
|
||||
}
|
||||
|
||||
if (client_id == ws_recv_data.client_id) {
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
'WS: Message received was sent by self and is an echo that can be ignored.'
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ws_recv_data.type == 'cmd') {
|
||||
console.log(`WS: Type CMD: ${ws_recv_data.cmd}`);
|
||||
ws_received_list_cmd.unshift(ws_recv_data); // Add to the beginning of the list
|
||||
// ws_received_list_cmd.push(ws_recv_data); // Add to the end of the list
|
||||
ws_received_list_cmd = ws_received_list_cmd; // trigger Svelte update -2024-10-04
|
||||
} else {
|
||||
console.log('WS: Type other');
|
||||
ws_received_list_other.unshift(ws_recv_data); // Add to the beginning of the list
|
||||
// ws_received_list_other.push(ws_recv_data); // Add to the end of the list
|
||||
ws_received_list_other = ws_received_list_other; // trigger Svelte update -2024-10-04
|
||||
}
|
||||
|
||||
// dispatch('ws_recv', {
|
||||
// // 'client_id': ws_data.client_id, // The device or browser ID if available.
|
||||
// 'src': ws_recv_data.client_id, // The device or browser ID if available.
|
||||
// // 'account_id': ws_recv_data.account_id, // Essentially the person ID or user ID if available.
|
||||
// 'dest': group_id, // Destination client
|
||||
// 'target': ws_recv_data.target, // echo, dm (direct), grp (group), all (broadcast)
|
||||
// 'type': ws_recv_data.type, // Message type (msg, cmd, json, hello, bye)
|
||||
// // 'grp': ws_recv_data.grp, // Destination group
|
||||
// 'msg': ws_recv_data.msg, // Message string
|
||||
// 'cmd': ws_recv_data.cmd, // Command string
|
||||
// });
|
||||
ws_recv_status = {
|
||||
// 'client_id': ws_data.client_id, // The device or browser ID if available.
|
||||
src: ws_recv_data.client_id, // The device or browser ID if available.
|
||||
// 'account_id': ws_recv_data.account_id, // Essentially the person ID or user ID if available.
|
||||
dest: group_id, // Destination client
|
||||
target: ws_recv_data.target, // echo, dm (direct), grp (group), all (broadcast)
|
||||
type: ws_recv_data.type, // Message type (msg, cmd, json, hello, bye)
|
||||
// 'grp': ws_recv_data.grp, // Destination group
|
||||
msg: ws_recv_data.msg, // Message string
|
||||
cmd: ws_recv_data.cmd // Command string
|
||||
};
|
||||
};
|
||||
|
||||
ws_connection.onclose = function (event) {
|
||||
console.log('WS: connection closed');
|
||||
|
||||
ws_connection.send(
|
||||
JSON.stringify({
|
||||
client_id: client_id,
|
||||
target: 'all',
|
||||
type: 'hello',
|
||||
group_id: group_id,
|
||||
msg: `Client ${client_id} is disconnecting!`
|
||||
})
|
||||
);
|
||||
|
||||
ws_connect_status = 'disconnected';
|
||||
|
||||
let fake_ws_recv_data = {
|
||||
client_id: client_id,
|
||||
target: 'local',
|
||||
type: 'bye',
|
||||
group_id: group_id,
|
||||
msg: `LOCAL Client ${client_id} has disconnected!`
|
||||
};
|
||||
ws_received_list_other.unshift(fake_ws_recv_data);
|
||||
ws_received_list_other = ws_received_list_other; // trigger Svelte update -2024-10-04
|
||||
|
||||
// dispatch('ws_conn', {
|
||||
// 'status': 'disconnected'
|
||||
// });
|
||||
ws_conn_status = 'disconnected';
|
||||
|
||||
if (ws_connect) {
|
||||
if (ws_retry_count >= 10) {
|
||||
ws_retry_delay = ws_retry_delay += 4999; // Set to a very long time
|
||||
ws_retry_delay = Math.min(ws_retry_delay, 120000); // Max of 2 minutes
|
||||
console.log(
|
||||
`WS: Retry count exceeded. Increasing the delay. ws_retry_count=${ws_retry_count} ws_retry_delay=${ws_retry_delay}`
|
||||
);
|
||||
}
|
||||
setTimeout(function () {
|
||||
console.log('WS: Disconnected... Try again!');
|
||||
ws_retry_count += 1;
|
||||
ws_connect_group_id({
|
||||
group_id: group_id,
|
||||
client_id: client_id
|
||||
});
|
||||
console.log('WS: Again done?');
|
||||
}, ws_retry_delay);
|
||||
}
|
||||
};
|
||||
|
||||
ws_connection.onerror = function (event) {
|
||||
console.log('WS: connection error???');
|
||||
|
||||
ws_connection.send(
|
||||
JSON.stringify({
|
||||
client_id: client_id,
|
||||
target: 'all',
|
||||
type: 'hello',
|
||||
group_id: group_id,
|
||||
msg: `Client ${client_id} is having trouble?!`
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
// NOTE WARNING: Uncommenting this seems to break FastAPI somehow???
|
||||
// NOTE: from FastAPI log: RuntimeError: Unexpected ASGI message 'websocket.send', after sending 'websocket.close'.
|
||||
// ws_connection.onerror = function(err) {
|
||||
// console.error('WS socket error: ', err.message, 'Closing socket');
|
||||
// // ws_connection.close();
|
||||
// };
|
||||
|
||||
return ws_connection;
|
||||
}
|
||||
|
||||
// Start the WS function
|
||||
let ws_group: any = $state(null);
|
||||
|
||||
function handle_send_ws_data() {
|
||||
console.log(ws_data);
|
||||
if (!ws_data) {
|
||||
return false;
|
||||
}
|
||||
if (!ws_group) {
|
||||
console.log('WS: No connection!');
|
||||
return false;
|
||||
}
|
||||
let ws_data_json_str = JSON.stringify(ws_data);
|
||||
let resp = ws_group.send(ws_data_json_str);
|
||||
console.log(`WS: Send data response:`, resp);
|
||||
|
||||
// dispatch('ws_sent', {
|
||||
// // 'client_id': ws_data.client_id, // The device or browser ID if available.
|
||||
// 'src': ws_data.client_id, // The device or browser ID if available.
|
||||
// // 'account_id': ws_data.account_id, // Essentially the person ID or user ID if available.
|
||||
// 'dest': group_id, // Destination client
|
||||
// 'group_id': group_id,
|
||||
// 'target': ws_data.target, // echo, dm (direct), grp (group), all (broadcast)
|
||||
// 'type': ws_data.type, // Message type (msg, cmd, json, hello, bye)
|
||||
// // 'grp': ws_data.grp, // Destination group
|
||||
// 'msg': ws_data.msg, // Message string
|
||||
// 'cmd': ws_data.cmd, // Command string
|
||||
// });
|
||||
ws_sent_status = {
|
||||
// 'client_id': ws_data.client_id, // The device or browser ID if available.
|
||||
src: ws_data.client_id, // The device or browser ID if available.
|
||||
// 'account_id': ws_data.account_id, // Essentially the person ID or user ID if available.
|
||||
dest: group_id, // Destination client
|
||||
group_id: group_id,
|
||||
target: ws_data.target, // echo, dm (direct), grp (group), all (broadcast)
|
||||
type: ws_data.type, // Message type (msg, cmd, json, hello, bye)
|
||||
// 'grp': ws_data.grp, // Destination group
|
||||
msg: ws_data.msg, // Message string
|
||||
cmd: ws_data.cmd // Command string
|
||||
};
|
||||
|
||||
cmd = '';
|
||||
msg = '';
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
if (ws_connect && group_id) {
|
||||
console.log('HERE!!!!!');
|
||||
ws_group = ws_connect_group_id({
|
||||
group_id: group_id,
|
||||
client_id: client_id
|
||||
});
|
||||
// } else if (!ws_connect) {
|
||||
// console.log('HERE!!!!!');
|
||||
// log_lvl = 1;
|
||||
// if (log_lvl) {
|
||||
// console.log(`WS: WS not set to connect. Need to close WS Group connection.`);
|
||||
// }
|
||||
// ws_group?.close();
|
||||
// ws_connect_status = 'disconnected';
|
||||
} else {
|
||||
console.log('HERE!!!!!');
|
||||
log_lvl = 1;
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`WS: Not connecting. ws_connect=${ws_connect} group_id=${group_id}`
|
||||
);
|
||||
}
|
||||
ws_group?.close();
|
||||
ws_connect_status = 'disconnected';
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (trigger_send && cmd) {
|
||||
trigger_send = null;
|
||||
console.log('WS: Send triggered!');
|
||||
console.log(cmd);
|
||||
ws_data.target = 'group';
|
||||
ws_data.type = 'cmd';
|
||||
ws_data.cmd = cmd;
|
||||
handle_send_ws_data();
|
||||
cmd = '';
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (trigger_connect) {
|
||||
trigger_connect = false;
|
||||
if (!ws_connect) {
|
||||
ws_connect = true;
|
||||
}
|
||||
console.log('WS: Connect triggered!');
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (trigger_disconnect) {
|
||||
console.log('WS: Disconnect triggered!');
|
||||
trigger_disconnect = false;
|
||||
if (ws_connect) {
|
||||
ws_connect = false;
|
||||
}
|
||||
if (ws_group) {
|
||||
ws_group.close();
|
||||
ws_group = null;
|
||||
ws_connect_status = 'disconnected';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function prevent_default<T extends Event>(fn: (event: T) => void) {
|
||||
return function (event: T) {
|
||||
event.preventDefault();
|
||||
fn(event);
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<section
|
||||
class:hidden={!ws_connect || hide__ws_element}
|
||||
class="ae_element__websocket container p-1 bg-pink-100 text-xs mx-auto pb-16 mt-32 mb-32 relative"
|
||||
>
|
||||
<span class="absolute top-0 right-0 flex flex-col gap-1">
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
hide__ws_form = !hide__ws_form;
|
||||
}}
|
||||
class="btn btn-sm text-xs hover:preset-filled-tertiary-500"
|
||||
class:preset-tonal-tertiary={hide__ws_form}
|
||||
class:preset-filled-tertiary-500={!hide__ws_form}
|
||||
>
|
||||
{#if hide__ws_form}
|
||||
Show Form
|
||||
{:else}
|
||||
Hide Form?
|
||||
{/if}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
hide__ws_messages = !hide__ws_messages;
|
||||
}}
|
||||
class="btn btn-sm text-xs hover:preset-filled-tertiary-500"
|
||||
class:preset-tonal-tertiary={hide__ws_messages}
|
||||
class:preset-filled-tertiary-500={!hide__ws_messages}
|
||||
>
|
||||
{#if hide__ws_messages}
|
||||
Show Messages
|
||||
{:else}
|
||||
Hide Messages?
|
||||
{/if}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
hide__ws_commands = !hide__ws_commands;
|
||||
}}
|
||||
class="btn btn-sm text-xs hover:preset-filled-tertiary-500"
|
||||
class:preset-tonal-tertiary={hide__ws_commands}
|
||||
class:preset-filled-tertiary-500={!hide__ws_commands}
|
||||
>
|
||||
{#if hide__ws_commands}
|
||||
Show Commands
|
||||
{:else}
|
||||
Hide Commands?
|
||||
{/if}
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<header>
|
||||
<h1 class="h6 text-center">Websocket Messages & Commands</h1>
|
||||
</header>
|
||||
|
||||
<!-- <form on:submit|prevent_default={handle_send_message}>
|
||||
<select bind:value={type}>
|
||||
<option value="">None</option>
|
||||
<option value="echo">Echo</option>
|
||||
<option value="dm">Direct Message</option>
|
||||
<option value="group">Group Message</option>
|
||||
<option value="all">Broadcast to All</option>
|
||||
<option value="cmd">Command</option>
|
||||
</select>
|
||||
|
||||
<select bind:value={group_id}>
|
||||
<option value="">None</option>
|
||||
<option value="test_grp_123">123</option>
|
||||
<option value="test_grp_999">999</option>
|
||||
<option value="test_grp_poster">A Poster Group</option>
|
||||
</select>
|
||||
|
||||
<input type="text" bind:value={message_text} placeholder="Your message"/>
|
||||
|
||||
<button>Send</button>
|
||||
</form> -->
|
||||
|
||||
{#if !hide__ws_form}
|
||||
<form onsubmit={prevent_default(handle_send_ws_data)}>
|
||||
<select bind:value={ws_data.type} class="input text-sm w-24">
|
||||
<option value="">None</option>
|
||||
<option value="echo">Echo</option>
|
||||
<option value="dm">Direct Message</option>
|
||||
<option value="group">Group Message</option>
|
||||
<option value="all">Broadcast to All</option>
|
||||
<option value="cmd">Command</option>
|
||||
</select>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={group_id}
|
||||
placeholder="Group ID"
|
||||
class="input text-sm w-36"
|
||||
/>
|
||||
<!-- <select bind:value={group_id}>
|
||||
<option value="">None</option>
|
||||
<option value="test_grp_123">123</option>
|
||||
<option value="test_grp_999">999</option>
|
||||
<option value="test_grp_poster">A Poster Group</option>
|
||||
</select> -->
|
||||
|
||||
<!-- <input type="text" bind:value={dm_client_id} placeholder="Direct message client ID"/> -->
|
||||
|
||||
<input
|
||||
type="text"
|
||||
bind:value={ws_data.cmd}
|
||||
placeholder="Your command"
|
||||
class="input text-sm w-36"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={ws_data.msg}
|
||||
placeholder="Your message"
|
||||
class="input text-xs w-96"
|
||||
/>
|
||||
|
||||
<button type="submit" class="btn btn-sm preset-tonal-warning"
|
||||
>Send Group</button
|
||||
>
|
||||
</form>
|
||||
{/if}
|
||||
|
||||
<!-- <pre>
|
||||
ae_load:event_session=jEG9APQRUs8 (Poster Session #3: Work Never Ends - Pythagoras)
|
||||
ae_open:event_file=CHqU5sW7xbc (jpg)
|
||||
ae_open:event_file=Kljq0uiTlXt (video)
|
||||
</pre> -->
|
||||
|
||||
<!-- <hr> -->
|
||||
|
||||
<section class:hidden={hide__ws_messages}>
|
||||
<h2 class="text-center underline">
|
||||
Messages [grp, client, target, type]
|
||||
</h2>
|
||||
|
||||
<ol class="list-decimal list-outside max-h-24 overflow-y-auto messages">
|
||||
{#each ws_received_list_other as msg_entry, index (index)}
|
||||
<li class="ml-4">
|
||||
<div class="flex flex-row justify-between gap-1 w-full">
|
||||
<span>
|
||||
[{msg_entry.group_id || 'No Group ID'}]
|
||||
{msg_entry.client_id.toString().slice(-5) ||
|
||||
'No Client ID'}
|
||||
–
|
||||
{msg_entry.target || 'No Target'}
|
||||
|
|
||||
<!-- – -->
|
||||
{msg_entry.type || 'No Type'}:
|
||||
</span>
|
||||
<span class="justify-self-end">
|
||||
"{msg_entry.msg}"
|
||||
</span>
|
||||
<!-- <br>{JSON.stringify(msg_entry)} -->
|
||||
</div>
|
||||
</li>
|
||||
{/each}
|
||||
</ol>
|
||||
</section>
|
||||
<!-- End Messages -->
|
||||
|
||||
<hr />
|
||||
|
||||
<section class:hidden={hide__ws_commands}>
|
||||
<h2 class="text-center underline">Commands</h2>
|
||||
|
||||
<ol class="list-decimal list-outside max-h-24 overflow-y-auto commands">
|
||||
{#each ws_received_list_cmd as cmd_entry, index (index)}
|
||||
<li class="ml-4">
|
||||
<div class="flex flex-row justify-between gap-1 w-full">
|
||||
<span>
|
||||
[{cmd_entry.group_id || 'No Group ID'}]
|
||||
{cmd_entry.client_id.toString().slice(-5) ||
|
||||
'No Client ID'}
|
||||
—
|
||||
{cmd_entry.target || 'No Target'}
|
||||
|
|
||||
<!-- — -->
|
||||
{cmd_entry.type || 'No Type'}:
|
||||
</span>
|
||||
<span class="justify-self-end">
|
||||
"{cmd_entry.cmd}"
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
{/each}
|
||||
</ol>
|
||||
</section>
|
||||
<!-- End Commands -->
|
||||
</section>
|
||||
|
||||
<style>
|
||||
/* .websocket_element {
|
||||
background-color: white;
|
||||
border-top: dashed medium gray;
|
||||
color: gray;
|
||||
font-size: .7em;
|
||||
}
|
||||
.websocket_element header {
|
||||
font-size: .7em;
|
||||
}
|
||||
.websocket_element h2 {
|
||||
font-size: .9em;
|
||||
} */
|
||||
</style>
|
||||
@@ -10,7 +10,7 @@
|
||||
import { Library, LoaderCircle, QrCode, RemoveFormatting, Search } from '@lucide/svelte';
|
||||
import { ae_loc, ae_api } from '$lib/stores/ae_stores';
|
||||
import { events_loc, events_sess } from '$lib/stores/ae_events_stores';
|
||||
import Element_qr_scanner_v3 from '$lib/element_qr_scanner_v3.svelte';
|
||||
import Element_qr_scanner_v3 from '$lib/elements/element_qr_scanner_v3.svelte';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
|
||||
// ISHLT 2024 badge type codes
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
import { ae_api } from '$lib/stores/ae_stores';
|
||||
import { events_loc } from '$lib/stores/ae_events_stores';
|
||||
import { events_func } from '$lib/ae_events_functions';
|
||||
import Element_qr_scanner_v3 from '$lib/element_qr_scanner_v3.svelte';
|
||||
import Element_qr_scanner_v3 from '$lib/elements/element_qr_scanner_v3.svelte';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import { CircleAlert, CircleCheck, Eye, LoaderCircle, ShieldOff, UserPlus } from '@lucide/svelte';
|
||||
import type { ae_EventBadge } from '$lib/types/ae_types';
|
||||
|
||||
Reference in New Issue
Block a user