|  |  | @ -112,62 +112,83 @@ import { accessToken } from "@/libs/crypto"; | 
			
		
	
		
			
				
					|  |  |  | import { IIdentifier } from "@veramo/core"; | 
			
		
	
		
			
				
					|  |  |  | import InfiniteScroll from "@/components/InfiniteScroll"; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | /** | 
			
		
	
		
			
				
					|  |  |  |  * Represents data about a project | 
			
		
	
		
			
				
					|  |  |  |  **/ | 
			
		
	
		
			
				
					|  |  |  | interface ProjectData { | 
			
		
	
		
			
				
					|  |  |  |   /** | 
			
		
	
		
			
				
					|  |  |  |    * Name of the project | 
			
		
	
		
			
				
					|  |  |  |    **/ | 
			
		
	
		
			
				
					|  |  |  |   name: string; | 
			
		
	
		
			
				
					|  |  |  |   /** | 
			
		
	
		
			
				
					|  |  |  |    * Description of the project | 
			
		
	
		
			
				
					|  |  |  |    **/ | 
			
		
	
		
			
				
					|  |  |  |   description: string; | 
			
		
	
		
			
				
					|  |  |  |   /** | 
			
		
	
		
			
				
					|  |  |  |    * URL referencing information about the project | 
			
		
	
		
			
				
					|  |  |  |    **/ | 
			
		
	
		
			
				
					|  |  |  |   handleId: string; | 
			
		
	
		
			
				
					|  |  |  |   /** | 
			
		
	
		
			
				
					|  |  |  |    * The Identier of the project | 
			
		
	
		
			
				
					|  |  |  |    **/ | 
			
		
	
		
			
				
					|  |  |  |   rowid: string; | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | @Component({ | 
			
		
	
		
			
				
					|  |  |  |   components: { InfiniteScroll }, | 
			
		
	
		
			
				
					|  |  |  | }) | 
			
		
	
		
			
				
					|  |  |  | export default class ProjectsView extends Vue { | 
			
		
	
		
			
				
					|  |  |  |   apiServer = ""; | 
			
		
	
		
			
				
					|  |  |  |   projects: { handleId: string; name: string; description: string }[] = []; | 
			
		
	
		
			
				
					|  |  |  |   projects: ProjectData[] = []; | 
			
		
	
		
			
				
					|  |  |  |   current: IIdentifier; | 
			
		
	
		
			
				
					|  |  |  |   isDataLoaded = false; | 
			
		
	
		
			
				
					|  |  |  |   isLoading = false; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   /** | 
			
		
	
		
			
				
					|  |  |  |    * Core project data loader | 
			
		
	
		
			
				
					|  |  |  |    * @param url the url used to fetch the data | 
			
		
	
		
			
				
					|  |  |  |    * @param token Authorization token | 
			
		
	
		
			
				
					|  |  |  |    **/ | 
			
		
	
		
			
				
					|  |  |  |   async dataLoader(url: string, token: string) { | 
			
		
	
		
			
				
					|  |  |  |     const headers: { [key: string]: string } = { | 
			
		
	
		
			
				
					|  |  |  |       "Content-Type": "application/json", | 
			
		
	
		
			
				
					|  |  |  |       Authorization: `Bearer ${token}`, | 
			
		
	
		
			
				
					|  |  |  |     }; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     try { | 
			
		
	
		
			
				
					|  |  |  |       this.isLoading = true; | 
			
		
	
		
			
				
					|  |  |  |       const resp = await this.axios.get(url, { headers }); | 
			
		
	
		
			
				
					|  |  |  |       if (resp.status === 200) { | 
			
		
	
		
			
				
					|  |  |  |         const plans: ProjectData[] = resp.data.data; | 
			
		
	
		
			
				
					|  |  |  |         for (const plan of plans) { | 
			
		
	
		
			
				
					|  |  |  |           const { name, description, handleId = plan.fullIri, rowid } = plan; | 
			
		
	
		
			
				
					|  |  |  |           this.projects.push({ name, description, handleId, rowid }); | 
			
		
	
		
			
				
					|  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |     } catch (error) { | 
			
		
	
		
			
				
					|  |  |  |       console.error("Got error loading projects:", error); | 
			
		
	
		
			
				
					|  |  |  |     } finally { | 
			
		
	
		
			
				
					|  |  |  |       this.isLoading = false; | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   /** | 
			
		
	
		
			
				
					|  |  |  |    * Data loader used by infinite scroller | 
			
		
	
		
			
				
					|  |  |  |    * @param payload is the flag from the InfiniteScroll indicating if it should load | 
			
		
	
		
			
				
					|  |  |  |    **/ | 
			
		
	
		
			
				
					|  |  |  |   async loadMoreData(payload: boolean) { | 
			
		
	
		
			
				
					|  |  |  |     console.log("loadMoreData"); | 
			
		
	
		
			
				
					|  |  |  |     console.log(payload); | 
			
		
	
		
			
				
					|  |  |  |     if (this.projects.length > 0) { | 
			
		
	
		
			
				
					|  |  |  |       console.log(this.projects[this.projects.length - 1]); | 
			
		
	
		
			
				
					|  |  |  |       const afterurl = this.projects[this.projects.length - 1]["handleId"]; | 
			
		
	
		
			
				
					|  |  |  |       const regex = /([0-9A-Z]+)$/; // Regular expression to match one or more digits at the end | 
			
		
	
		
			
				
					|  |  |  |       const matches = afterurl.match(regex); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |       let afterId = ""; | 
			
		
	
		
			
				
					|  |  |  |       if (matches && matches.length > 1) { | 
			
		
	
		
			
				
					|  |  |  |         afterId = matches[1]; | 
			
		
	
		
			
				
					|  |  |  |         console.log(afterId); // Output: 01H3HBVZGH3YE0K27X35S15QT1 | 
			
		
	
		
			
				
					|  |  |  |       } else { | 
			
		
	
		
			
				
					|  |  |  |         console.log("No digits found at the end of the URL."); | 
			
		
	
		
			
				
					|  |  |  |         return; | 
			
		
	
		
			
				
					|  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |       const url = | 
			
		
	
		
			
				
					|  |  |  |         this.apiServer + "/api/v2/report/plansByIssuer?afterId=" + afterId; | 
			
		
	
		
			
				
					|  |  |  |       const latestProject = this.projects[this.projects.length - 1]; | 
			
		
	
		
			
				
					|  |  |  |       const url = `${this.apiServer}/api/v2/report/plansByIssuer?beforeId=${latestProject.rowid}`; | 
			
		
	
		
			
				
					|  |  |  |       const token = await accessToken(this.current); | 
			
		
	
		
			
				
					|  |  |  |       const headers = { | 
			
		
	
		
			
				
					|  |  |  |         "Content-Type": "application/json", | 
			
		
	
		
			
				
					|  |  |  |         Authorization: "Bearer " + token, | 
			
		
	
		
			
				
					|  |  |  |       }; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |       try { | 
			
		
	
		
			
				
					|  |  |  |         const resp = await this.axios.get(url, { headers }); | 
			
		
	
		
			
				
					|  |  |  |         if (resp.status === 200) { | 
			
		
	
		
			
				
					|  |  |  |           const plans = resp.data.data; | 
			
		
	
		
			
				
					|  |  |  |           for (let i = 0; i < plans.length; i++) { | 
			
		
	
		
			
				
					|  |  |  |             const plan = plans[i]; | 
			
		
	
		
			
				
					|  |  |  |             const data = { | 
			
		
	
		
			
				
					|  |  |  |               name: plan.name, | 
			
		
	
		
			
				
					|  |  |  |               description: plan.description, | 
			
		
	
		
			
				
					|  |  |  |               // handleId is new in server v release-1.6.0; remove fullIri when that | 
			
		
	
		
			
				
					|  |  |  |               // version shows up here: https://endorser.ch:3000/api-docs/ | 
			
		
	
		
			
				
					|  |  |  |               handleId: plan.handleId || plan.fullIri, | 
			
		
	
		
			
				
					|  |  |  |             }; | 
			
		
	
		
			
				
					|  |  |  |             this.projects.push(data); | 
			
		
	
		
			
				
					|  |  |  |           } | 
			
		
	
		
			
				
					|  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |       } catch (error) { | 
			
		
	
		
			
				
					|  |  |  |         console.error("Got error loading projects: ", error); | 
			
		
	
		
			
				
					|  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |       await this.dataLoader(url, token); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   /** | 
			
		
	
		
			
				
					|  |  |  |   * Handle clicking on a project entry found in the list | 
			
		
	
		
			
				
					|  |  |  |   * @param id of the project | 
			
		
	
		
			
				
					|  |  |  |   **? | 
			
		
	
		
			
				
					|  |  |  |   onClickLoadProject(id: string) { | 
			
		
	
		
			
				
					|  |  |  |     localStorage.setItem("projectId", id); | 
			
		
	
		
			
				
					|  |  |  |     const route = { | 
			
		
	
	
		
			
				
					|  |  | @ -176,39 +197,20 @@ export default class ProjectsView extends Vue { | 
			
		
	
		
			
				
					|  |  |  |     this.$router.push(route); | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   /** | 
			
		
	
		
			
				
					|  |  |  |   * Load projects initially | 
			
		
	
		
			
				
					|  |  |  |   * @param identity of the user | 
			
		
	
		
			
				
					|  |  |  |   **/ | 
			
		
	
		
			
				
					|  |  |  |   async LoadProjects(identity: IIdentifier) { | 
			
		
	
		
			
				
					|  |  |  |     console.log("LoadProjects"); | 
			
		
	
		
			
				
					|  |  |  |     const url = this.apiServer + "/api/v2/report/plansByIssuer"; | 
			
		
	
		
			
				
					|  |  |  |     const token = await accessToken(identity); | 
			
		
	
		
			
				
					|  |  |  |     const headers = { | 
			
		
	
		
			
				
					|  |  |  |       "Content-Type": "application/json", | 
			
		
	
		
			
				
					|  |  |  |       Authorization: "Bearer " + token, | 
			
		
	
		
			
				
					|  |  |  |     }; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     try { | 
			
		
	
		
			
				
					|  |  |  |       const resp = await this.axios.get(url, { headers }); | 
			
		
	
		
			
				
					|  |  |  |       if (resp.status === 200) { | 
			
		
	
		
			
				
					|  |  |  |         const plans = resp.data.data; | 
			
		
	
		
			
				
					|  |  |  |         for (let i = 0; i < plans.length; i++) { | 
			
		
	
		
			
				
					|  |  |  |           const plan = plans[i]; | 
			
		
	
		
			
				
					|  |  |  |           const data = { | 
			
		
	
		
			
				
					|  |  |  |             name: plan.name, | 
			
		
	
		
			
				
					|  |  |  |             description: plan.description, | 
			
		
	
		
			
				
					|  |  |  |             // handleId is new in server v release-1.6.0; remove fullIri when that | 
			
		
	
		
			
				
					|  |  |  |             // version shows up here: https://endorser.ch:3000/api-docs/ | 
			
		
	
		
			
				
					|  |  |  |             handleId: plan.handleId || plan.fullIri, | 
			
		
	
		
			
				
					|  |  |  |           }; | 
			
		
	
		
			
				
					|  |  |  |           this.projects.push(data); | 
			
		
	
		
			
				
					|  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         this.isDataLoaded = true; | 
			
		
	
		
			
				
					|  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |     } catch (error) { | 
			
		
	
		
			
				
					|  |  |  |       console.error("Got error loading projects: ", error); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     const url = `${this.apiServer}/api/v2/report/plansByIssuer`; | 
			
		
	
		
			
				
					|  |  |  |     const token: string = await accessToken(identity); | 
			
		
	
		
			
				
					|  |  |  |     await this.dataLoader(url, token); | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   // 'created' hook runs when the Vue instance is first created | 
			
		
	
		
			
				
					|  |  |  |   /** | 
			
		
	
		
			
				
					|  |  |  |    * 'created' hook runs when the Vue instance is first created | 
			
		
	
		
			
				
					|  |  |  |    **/ | 
			
		
	
		
			
				
					|  |  |  |   async created() { | 
			
		
	
		
			
				
					|  |  |  |     await db.open(); | 
			
		
	
		
			
				
					|  |  |  |     const settings = await db.settings.get(MASTER_SETTINGS_KEY); | 
			
		
	
	
		
			
				
					|  |  | @ -230,6 +232,9 @@ export default class ProjectsView extends Vue { | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   /** | 
			
		
	
		
			
				
					|  |  |  |    * Handling clicking on the new project button | 
			
		
	
		
			
				
					|  |  |  |    **/ | 
			
		
	
		
			
				
					|  |  |  |   onClickNewProject(): void { | 
			
		
	
		
			
				
					|  |  |  |     localStorage.removeItem("projectId"); | 
			
		
	
		
			
				
					|  |  |  |     const route = { | 
			
		
	
	
		
			
				
					|  |  | 
 |