Skip to content

Instantly share code, notes, and snippets.

@SugarDarius
Last active November 5, 2018 09:23
Show Gist options
  • Save SugarDarius/233393e76c8065fa4a9b8bd17fd19006 to your computer and use it in GitHub Desktop.
Save SugarDarius/233393e76c8065fa4a9b8bd17fd19006 to your computer and use it in GitHub Desktop.
A React component to detect browsers and update UI
/*
* Detect browser - Browsers
* author: Aurélien Dupays Dexemple
*/
export type BrowserName = 'Chrome' |
'Firefox' |
'Safari' |
'Internet Explorer' |
'Opera' |
'BlackBerry' |
'Mozilla';
export interface Browser {
name: BrowserName;
value: string;
version: string;
}
export const browsers: Browser[] = [
{ name: 'Chrome', value: 'Chrome', version: 'Chrome' },
{ name: 'Firefox', value: 'Firefox', version: 'Firefox' },
{ name: 'Safari', value: 'Safari', version: 'Version' },
{ name: 'Internet Explorer', value: 'MSIE', version: 'MSIE' },
{ name: 'Opera', value: 'Opera', version: 'Opera' },
{ name: 'BlackBerry', value: 'CLDC', version: 'CLDC' },
{ name: 'Mozilla', value: 'Mozilla', version: 'Mozilla' }
];
/*
* Detect browser
* author: Aurélien Dupays Dexemple
*/
import './stylesheet.scss';
import * as React from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import every = require('lodash/every');
import { OperatingSystemName } from './operating-systems';
import { BrowserName } from './browsers';
import { DetectBrowserResult, detectBrowser } from './detect-browser';
export interface DetectBrowserBlackListItem {
name: BrowserName;
version: number | 'any';
os?: {
name: OperatingSystemName;
version: number | 'any';
}
}
export interface DetectBrowserProps {
blacklist: DetectBrowserBlackListItem[];
children: JSX.Element[] | JSX.Element;
}
export class DetectBrowser extends React.PureComponent<DetectBrowserProps> {
allowBrowser = (): boolean => {
const { blacklist } = this.props;
const { platform, userAgent, appVersion, vendor } = navigator;
const detectBrowserResult: DetectBrowserResult = detectBrowser([platform, userAgent, appVersion, vendor]);
return every(blacklist, (item: DetectBrowserBlackListItem ) => (
!(
item.name === detectBrowserResult.browser.name &&
(item.version !== 'any' ? item.version === detectBrowserResult.browser.version : false) &&
(item.os ? item.os.name === detectBrowserResult.os.name : false) &&
(item.os && item.os.version !== 'any' ? item.os.version === detectBrowserResult.os.version : false )
)
));
}
render(): JSX.Element {
const { children } = this.props;
const browserIsAllowed: boolean = this.allowBrowser();
return (
<React.Fragment>
{
!browserIsAllowed ? (
<div className='detect-browser-box'>
<div className='detect-browser-box__content fa-4x'>
<div className='fa-2x' style={{ marginBottom: 44 }}>
<span className='fa-layers fa-fw'>
<FontAwesomeIcon
className='detect-browser-box__content__icons'
icon='desktop'
transform='shrink-8'
/>
<FontAwesomeIcon
className='detect-browser-box__content__icons'
icon='ban'
style={{ color: 'Tomato' }}
transform='grow-2'
/>
</span>
</div>
<span className='detect-browser-box__content__message'>
We are sorry, our application does not support Internet Explorer.<br />
Please, try opening it with a more recent browser.
</span>
</div>
</div>
) : children
}
</React.Fragment>
)
}
}
/*
* Detect browser - main algorithm
* author: Aurélien Dupays Dexemple
*/
import { OperatingSystem, operatingSystems } from './operating-systems';
import { Browser, browsers } from './browsers';
export type Agent = string;
export type DataItems = OperatingSystem[] | Browser[];
export interface DetectBrowserResultItem {
name: string;
version: number;
}
export interface DetectBrowserResult {
os: DetectBrowserResultItem;
browser: DetectBrowserResultItem;
}
const getMatches = (agents: Agent[], data: DataItems): DetectBrowserResultItem => {
let resultItem: DetectBrowserResultItem = { name: 'unknonw', version: -1 };
const _agents: string = agents.join(' ');
let match: boolean = false, matches: RegExpMatchArray | null = null, index: number = 0;
const getVersion = (matches: RegExpMatchArray | null = null): number => {
const _matches: string | null = matches && matches[1] ? matches[1] : null;
return _matches ? Number.parseInt(_matches.split(/[._]+/)[0]) : -1;
};
while (!match && index < data.length) {
const item = data[index];
match = (new RegExp(item.value, 'i')).test(_agents);
if (match) {
matches = _agents.match(new RegExp(`${item.version}[- /:;]([\\d._]+)`, 'i'));
resultItem.name = item.name;
resultItem.version = getVersion(matches);
break;
}
index = index + 1;
}
return resultItem;
}
export const detectBrowser = (agents: Agent[]): DetectBrowserResult => ({
os: getMatches(agents, operatingSystems),
browser: getMatches(agents, browsers)
})
/*
* Detect browser - Operating systems
* author: Aurélien Dupays Dexemple
*/
export type OperatingSystemName = 'Windows Phone' |
'Windows' |
'iPhone' |
'iPad' |
'Kindle' |
'Android' |
'PlayBook' |
'BlackBerry' |
'Macintosh' |
'Linux' |
'Palm';
export interface OperatingSystem {
name: OperatingSystemName;
value: string;
version: string;
};
export const operatingSystems: OperatingSystem[] = [
{ name: 'Windows Phone', value: 'Windows Phone', version: 'OS' },
{ name: 'Windows', value: 'Win', version: 'NT' },
{ name: 'iPhone', value: 'iPhone', version: 'OS' },
{ name: 'iPad', value: 'iPad', version: 'OS' },
{ name: 'Kindle', value: 'Silk', version: 'Silk' },
{ name: 'Android', value: 'Android', version: 'Android' },
{ name: 'PlayBook', value: 'PlayBook', version: 'OS' },
{ name: 'BlackBerry', value: 'BlackBerry', version: '/' },
{ name: 'Macintosh', value: 'Mac', version: 'OS X' },
{ name: 'Linux', value: 'Linux', version: 'rv' },
{ name: 'Palm', value: 'Palm', version: 'PalmOS' }
];
/*
* Detect browser - stylesheet
* author: Aurélien Dupays Dexemple
*/
@import '../../shared/stylesheets/colors.scss';
@import '../../shared/stylesheets/mixins.scss';
.detect-browser-box {
position: fixed;
top: 0;
left: 0;
display: flex !important;
flex-direction: column !important;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
background-color: $gray-9;
z-index: 99999;
overflow: hidden !important;
&__content {
position: relative;
display: flex !important;
flex-direction: column !important;
justify-content: center;
align-items: center;
width: 80%;
max-width: 800px;
min-height: 200px;
padding: 54px 16px;
border-radius: 3px;
border: solid 1px $gray-7;
background-color: $white-0;
&__icons { color: $gray-1; }
&__message {
text-align: center;
@include font($EtelkaTextPro, 300, 22px);
color: $gray-1;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment