forked from vergnet/application-amicale
		
	
		
			
				
	
	
		
			232 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			232 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2019 - 2020 Arnaud Vergnet.
 | |
|  *
 | |
|  * This file is part of Campus INSAT.
 | |
|  *
 | |
|  * Campus INSAT is free software: you can redistribute it and/or modify
 | |
|  *  it under the terms of the GNU General Public License as published by
 | |
|  * the Free Software Foundation, either version 3 of the License, or
 | |
|  * (at your option) any later version.
 | |
|  *
 | |
|  * Campus INSAT is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
 | |
|  */
 | |
| 
 | |
| import { Linking } from 'react-native';
 | |
| import {
 | |
|   ClubInformationScreenParams,
 | |
|   MainRoutes,
 | |
|   PlanningInformationScreenParams,
 | |
| } from '../navigation/MainNavigator';
 | |
| 
 | |
| export type ParsedUrlDataType = {
 | |
|   route: MainRoutes.ClubInformation | MainRoutes.PlanningInformation;
 | |
|   data: ClubInformationScreenParams | PlanningInformationScreenParams;
 | |
| };
 | |
| 
 | |
| export type ParsedUrlCallbackType = (parsedData: ParsedUrlDataType) => void;
 | |
| 
 | |
| type RawParsedUrlDataType = {
 | |
|   path: string;
 | |
|   queryParams: { [key: string]: string };
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Class use to handle depp links scanned or clicked.
 | |
|  */
 | |
| export default class URLHandler {
 | |
|   static SCHEME = 'campus-insat://'; // Urls beginning with this string will be opened in the app
 | |
| 
 | |
|   static CLUB_INFO_URL_PATH = 'club';
 | |
| 
 | |
|   static EVENT_INFO_URL_PATH = 'event';
 | |
| 
 | |
|   onInitialURLParsed: ParsedUrlCallbackType;
 | |
| 
 | |
|   onDetectURL: ParsedUrlCallbackType;
 | |
| 
 | |
|   constructor(
 | |
|     onInitialURLParsed: ParsedUrlCallbackType,
 | |
|     onDetectURL: ParsedUrlCallbackType
 | |
|   ) {
 | |
|     this.onInitialURLParsed = onInitialURLParsed;
 | |
|     this.onDetectURL = onDetectURL;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Parses the given url to retrieve the corresponding app path and associated arguments.
 | |
|    *
 | |
|    * @param url The url to parse
 | |
|    * @returns {{path: string, queryParams: {}}}
 | |
|    */
 | |
|   static parseUrl(url: string): RawParsedUrlDataType | null {
 | |
|     let parsedData: RawParsedUrlDataType | null = null;
 | |
|     const urlNoScheme = url.replace(URLHandler.SCHEME, '');
 | |
|     if (urlNoScheme != null) {
 | |
|       const params: { [key: string]: string } = {};
 | |
|       const [path, fullParamsString] = urlNoScheme.split('?');
 | |
|       if (fullParamsString != null) {
 | |
|         const paramsStringArray = fullParamsString.split('&');
 | |
|         paramsStringArray.forEach((paramString: string) => {
 | |
|           const [key, value] = paramString.split('=');
 | |
|           if (value != null) {
 | |
|             params[key] = value;
 | |
|           }
 | |
|         });
 | |
|       }
 | |
|       if (path != null) {
 | |
|         parsedData = { path, queryParams: params };
 | |
|       }
 | |
|     }
 | |
|     return parsedData;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Gets routing data corresponding to the given url.
 | |
|    * If the url does not match any existing route, null will be returned.
 | |
|    *
 | |
|    * @param rawParsedUrlData The data just parsed
 | |
|    * @returns {null}
 | |
|    */
 | |
|   static getUrlData(
 | |
|     rawParsedUrlData: RawParsedUrlDataType | null
 | |
|   ): ParsedUrlDataType | null {
 | |
|     let parsedData: null | ParsedUrlDataType = null;
 | |
|     if (rawParsedUrlData != null) {
 | |
|       const { path } = rawParsedUrlData;
 | |
|       const { queryParams } = rawParsedUrlData;
 | |
|       if (URLHandler.isClubInformationLink(path)) {
 | |
|         parsedData = URLHandler.generateClubInformationData(queryParams);
 | |
|       } else if (URLHandler.isPlanningInformationLink(path)) {
 | |
|         parsedData = URLHandler.generatePlanningInformationData(queryParams);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     return parsedData;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Checks if the given url is in a valid format
 | |
|    *
 | |
|    * @param url The url to check
 | |
|    * @returns {boolean}
 | |
|    */
 | |
|   static isUrlValid(url: string): boolean {
 | |
|     return this.getUrlData(URLHandler.parseUrl(url)) !== null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Check if the given path links to the club information screen
 | |
|    *
 | |
|    * @param path The url to check
 | |
|    * @returns {boolean}
 | |
|    */
 | |
|   static isClubInformationLink(path: string): boolean {
 | |
|     return path === URLHandler.CLUB_INFO_URL_PATH;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Check if the given path links to the planning information screen
 | |
|    *
 | |
|    * @param path The url to check
 | |
|    * @returns {boolean}
 | |
|    */
 | |
|   static isPlanningInformationLink(path: string): boolean {
 | |
|     return path === URLHandler.EVENT_INFO_URL_PATH;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Generates data formatted for the club information screen from the url parameters.
 | |
|    *
 | |
|    * @param params Url parameters to convert
 | |
|    * @returns {null|{route: string, data: {clubId: number}}}
 | |
|    */
 | |
|   static generateClubInformationData(params: {
 | |
|     [key: string]: string;
 | |
|   }): ParsedUrlDataType | null {
 | |
|     if (params.id != null) {
 | |
|       const id = parseInt(params.id, 10);
 | |
|       if (!Number.isNaN(id)) {
 | |
|         return {
 | |
|           route: MainRoutes.ClubInformation,
 | |
|           data: {
 | |
|             type: 'id',
 | |
|             clubId: id,
 | |
|           },
 | |
|         };
 | |
|       }
 | |
|     }
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Generates data formatted for the planning information screen from the url parameters.
 | |
|    *
 | |
|    * @param params Url parameters to convert
 | |
|    * @returns {null|{route: string, data: {clubId: number}}}
 | |
|    */
 | |
|   static generatePlanningInformationData(params: {
 | |
|     [key: string]: string;
 | |
|   }): ParsedUrlDataType | null {
 | |
|     if (params.id != null) {
 | |
|       const id = parseInt(params.id, 10);
 | |
|       if (!Number.isNaN(id)) {
 | |
|         return {
 | |
|           route: MainRoutes.PlanningInformation,
 | |
|           data: {
 | |
|             type: 'id',
 | |
|             eventId: id,
 | |
|           },
 | |
|         };
 | |
|       }
 | |
|     }
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Starts listening to events.
 | |
|    *
 | |
|    * There are 2 types of event.
 | |
|    *
 | |
|    * A classic event, triggered while the app is active.
 | |
|    * An initial event, called when the app was opened by clicking on a link
 | |
|    *
 | |
|    */
 | |
|   listen() {
 | |
|     Linking.addEventListener('url', this.onUrl);
 | |
|     Linking.getInitialURL().then(this.onInitialUrl);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Gets data from the given url and calls the classic callback with it.
 | |
|    *
 | |
|    * @param url The url detected
 | |
|    */
 | |
|   onUrl = ({ url }: { url: string }) => {
 | |
|     if (url != null) {
 | |
|       const data = URLHandler.getUrlData(URLHandler.parseUrl(url));
 | |
|       if (data != null) {
 | |
|         this.onDetectURL(data);
 | |
|       }
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   /**
 | |
|    * Gets data from the given url and calls the initial callback with it.
 | |
|    *
 | |
|    * @param url The url detected
 | |
|    */
 | |
|   onInitialUrl = (url: string | null) => {
 | |
|     if (url != null) {
 | |
|       const data = URLHandler.getUrlData(URLHandler.parseUrl(url));
 | |
|       if (data != null) {
 | |
|         this.onInitialURLParsed(data);
 | |
|       }
 | |
|     }
 | |
|   };
 | |
| }
 |