박선진

add front-end template code

going to fix it suitably for my project
Showing 436 changed files with 4816 additions and 0 deletions
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.idea/
This diff could not be displayed because it is too large.
module.exports = {
"presets": [
"react-app"
],
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-optional-chaining"
]
};
\ No newline at end of file
'use strict';
const fs = require('fs');
const path = require('path');
const paths = require('./paths');
// Make sure that including paths.js after env.js will read .env variables.
delete require.cache[require.resolve('./paths')];
const NODE_ENV = process.env.NODE_ENV;
if (!NODE_ENV) {
throw new Error(
'The NODE_ENV environment variable is required but was not specified.'
);
}
// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
var dotenvFiles = [
`${paths.dotenv}.${NODE_ENV}.local`,
`${paths.dotenv}.${NODE_ENV}`,
// Don't include `.env.local` for `test` environment
// since normally you expect tests to produce the same
// results for everyone
NODE_ENV !== 'test' && `${paths.dotenv}.local`,
paths.dotenv,
].filter(Boolean);
// Load environment variables from .env* files. Suppress warnings using silent
// if this file is missing. dotenv will never modify any environment variables
// that have already been set. Variable expansion is supported in .env files.
// https://github.com/motdotla/dotenv
// https://github.com/motdotla/dotenv-expand
dotenvFiles.forEach(dotenvFile => {
if (fs.existsSync(dotenvFile)) {
require('dotenv-expand')(
require('dotenv').config({
path: dotenvFile,
})
);
}
});
// We support resolving modules according to `NODE_PATH`.
// This lets you use absolute paths in imports inside large monorepos:
// https://github.com/facebook/create-react-app/issues/253.
// It works similar to `NODE_PATH` in Node itself:
// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
// Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims.
// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
// We also resolve them to make sure all tools using them work consistently.
const appDirectory = fs.realpathSync(process.cwd());
process.env.NODE_PATH = (process.env.NODE_PATH || '')
.split(path.delimiter)
.filter(folder => folder && !path.isAbsolute(folder))
.map(folder => path.resolve(appDirectory, folder))
.join(path.delimiter);
// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
// injected into the application via DefinePlugin in Webpack configuration.
const REACT_APP = /^REACT_APP_/i;
function getClientEnvironment(publicUrl) {
const raw = Object.keys(process.env)
.filter(key => REACT_APP.test(key))
.reduce(
(env, key) => {
env[key] = process.env[key];
return env;
},
{
// Useful for determining whether we’re running in production mode.
// Most importantly, it switches React into the correct mode.
NODE_ENV: process.env.NODE_ENV || 'development',
// Useful for resolving the correct path to static assets in `public`.
// For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />.
// This should only be used as an escape hatch. Normally you would put
// images into the `src` and `import` them in code to get their paths.
PUBLIC_URL: publicUrl,
}
);
// Stringify all values so we can feed into Webpack DefinePlugin
const stringified = {
'process.env': Object.keys(raw).reduce((env, key) => {
env[key] = JSON.stringify(raw[key]);
return env;
}, {}),
};
return { raw, stringified };
}
module.exports = getClientEnvironment;
'use strict';
// This is a custom Jest transformer turning style imports into empty objects.
// http://facebook.github.io/jest/docs/en/webpack.html
module.exports = {
process() {
return 'module.exports = {};';
},
getCacheKey() {
// The output is always the same.
return 'cssTransform';
},
};
'use strict';
const path = require('path');
// This is a custom Jest transformer turning file imports into filenames.
// http://facebook.github.io/jest/docs/en/webpack.html
module.exports = {
process(src, filename) {
const assetFilename = JSON.stringify(path.basename(filename));
if (filename.match(/\.svg$/)) {
return `module.exports = {
__esModule: true,
default: ${assetFilename},
ReactComponent: (props) => ({
$$typeof: Symbol.for('react.element'),
type: 'svg',
ref: null,
key: null,
props: Object.assign({}, props, {
children: ${assetFilename}
})
}),
};`;
}
return `module.exports = ${assetFilename};`;
},
};
'use strict';
const path = require('path');
const fs = require('fs');
const url = require('url');
// Make sure any symlinks in the project folder are resolved:
// https://github.com/facebook/create-react-app/issues/637
const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
const envPublicUrl = process.env.PUBLIC_URL;
function ensureSlash(inputPath, needsSlash) {
const hasSlash = inputPath.endsWith('/');
if (hasSlash && !needsSlash) {
return inputPath.substr(0, inputPath.length - 1);
} else if (!hasSlash && needsSlash) {
return `${inputPath}/`;
} else {
return inputPath;
}
}
const getPublicUrl = appPackageJson =>
envPublicUrl || require(appPackageJson).homepage;
// We use `PUBLIC_URL` environment variable or "homepage" field to infer
// "public path" at which the app is served.
// Webpack needs to know it to put the right <script> hrefs into HTML even in
// single-page apps that may serve index.html for nested URLs like /todos/42.
// We can't use a relative path in HTML because we don't want to load something
// like /todos/42/static/js/bundle.7289d.js. We have to know the root.
function getServedPath(appPackageJson) {
const publicUrl = getPublicUrl(appPackageJson);
const servedUrl =
envPublicUrl || (publicUrl ? url.parse(publicUrl).pathname : '/');
return ensureSlash(servedUrl, true);
}
// config after eject: we're in ./config/
module.exports = {
dotenv: resolveApp('.env'),
appPath: resolveApp('.'),
appBuild: resolveApp('build'),
appPublic: resolveApp('public'),
appHtml: resolveApp('public/index.html'),
appIndexJs: resolveApp('src/index.js'),
appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('src'),
yarnLockFile: resolveApp('yarn.lock'),
testsSetup: resolveApp('src/setupTests.js'),
proxySetup: resolveApp('src/setupProxy.js'),
appNodeModules: resolveApp('node_modules'),
publicUrl: getPublicUrl(resolveApp('package.json')),
servedPath: getServedPath(resolveApp('package.json')),
};
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
'use strict';
const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware');
const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware');
const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware');
const ignoredFiles = require('react-dev-utils/ignoredFiles');
const config = require('./webpack.config.dev');
const paths = require('./paths');
const fs = require('fs');
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const host = process.env.HOST || '0.0.0.0';
module.exports = function(proxy, allowedHost) {
return {
// WebpackDevServer 2.4.3 introduced a security fix that prevents remote
// websites from potentially accessing local content through DNS rebinding:
// https://github.com/webpack/webpack-dev-server/issues/887
// https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a
// However, it made several existing use cases such as development in cloud
// environment or subdomains in development significantly more complicated:
// https://github.com/facebook/create-react-app/issues/2271
// https://github.com/facebook/create-react-app/issues/2233
// While we're investigating better solutions, for now we will take a
// compromise. Since our WDS configuration only serves files in the `public`
// folder we won't consider accessing them a vulnerability. However, if you
// use the `proxy` feature, it gets more dangerous because it can expose
// remote code execution vulnerabilities in backends like Django and Rails.
// So we will disable the host check normally, but enable it if you have
// specified the `proxy` setting. Finally, we let you override it if you
// really know what you're doing with a special environment variable.
disableHostCheck:
!proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true',
// Enable gzip compression of generated files.
compress: true,
// Silence WebpackDevServer's own logs since they're generally not useful.
// It will still show compile warnings and errors with this setting.
clientLogLevel: 'none',
// By default WebpackDevServer serves physical files from current directory
// in addition to all the virtual build products that it serves from memory.
// This is confusing because those files won’t automatically be available in
// production build folder unless we copy them. However, copying the whole
// project directory is dangerous because we may expose sensitive files.
// Instead, we establish a convention that only files in `public` directory
// get served. Our build script will copy `public` into the `build` folder.
// In `index.html`, you can get URL of `public` folder with %PUBLIC_URL%:
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
// In JavaScript code, you can access it with `process.env.PUBLIC_URL`.
// Note that we only recommend to use `public` folder as an escape hatch
// for files like `favicon.ico`, `manifest.json`, and libraries that are
// for some reason broken when imported through Webpack. If you just want to
// use an image, put it in `src` and `import` it from JavaScript instead.
contentBase: paths.appPublic,
// By default files from `contentBase` will not trigger a page reload.
watchContentBase: true,
// Enable hot reloading server. It will provide /sockjs-node/ endpoint
// for the WebpackDevServer client so it can learn when the files were
// updated. The WebpackDevServer client is included as an entry point
// in the Webpack development configuration. Note that only changes
// to CSS are currently hot reloaded. JS changes will refresh the browser.
hot: true,
// It is important to tell WebpackDevServer to use the same "root" path
// as we specified in the config. In development, we always serve from /.
publicPath: config.output.publicPath,
// WebpackDevServer is noisy by default so we emit custom message instead
// by listening to the compiler events with `compiler.hooks[...].tap` calls above.
quiet: true,
// Reportedly, this avoids CPU overload on some systems.
// https://github.com/facebook/create-react-app/issues/293
// src/node_modules is not ignored to support absolute imports
// https://github.com/facebook/create-react-app/issues/1065
watchOptions: {
ignored: ignoredFiles(paths.appSrc),
},
// Enable HTTPS if the HTTPS environment variable is set to 'true'
https: protocol === 'https',
host,
overlay: false,
historyApiFallback: {
// Paths with dots should still use the history fallback.
// See https://github.com/facebook/create-react-app/issues/387.
disableDotRule: true,
},
public: allowedHost,
proxy,
before(app, server) {
if (fs.existsSync(paths.proxySetup)) {
// This registers user provided middleware for proxy reasons
require(paths.proxySetup)(app);
}
// This lets us fetch source contents from webpack for the error overlay
app.use(evalSourceMapMiddleware(server));
// This lets us open files from the runtime error overlay.
app.use(errorOverlayMiddleware());
// This service worker file is effectively a 'no-op' that will reset any
// previous service worker registered for the same host:port combination.
// We do this in development to avoid hitting the production cache if
// it used the same host and port.
// https://github.com/facebook/create-react-app/issues/2272#issuecomment-302832432
app.use(noopServiceWorkerMiddleware());
},
};
};
{
"name": "sing-app-react",
"version": "5.0.0",
"private": true,
"scripts": {
"build": "node scripts/build.js",
"start": "node scripts/start.js",
"test": "node scripts/test.js"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
],
"eslintConfig": {
"extends": "react-app"
},
"jest": {
"collectCoverageFrom": [
"src/**/*.{js,jsx}"
],
"moduleFileExtensions": [
"web.js",
"js",
"json",
"web.jsx",
"jsx",
"node"
],
"moduleNameMapper": {
"^react-native$": "react-native-web",
"^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy"
},
"resolver": "jest-pnp-resolver",
"setupFiles": [
"react-app-polyfill/jsdom"
],
"testEnvironment": "jsdom",
"testMatch": [
"<rootDir>/src/**/__tests__/**/*.{js,jsx}",
"<rootDir>/src/**/?(*.)(spec|test).{js,jsx}"
],
"testURL": "http://localhost",
"transform": {
"^.+\\.(js|jsx)$": "<rootDir>/node_modules/babel-jest",
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
"^(?!.*\\.(js|jsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
},
"transformIgnorePatterns": [
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$",
"^.+\\.module\\.(css|sass|scss)$"
]
},
"dependencies": {
"animate.css": "3.7.0",
"awesome-bootstrap-checkbox": "1.0.1",
"axios": "^0.18.0",
"bootstrap": "4.0.0",
"bootstrap-slider": "^10.2.1",
"bootstrap_calendar": "https://github.com/xero/bootstrap_calendar.git#1.0.1",
"classnames": "^2.2.6",
"draft-js": "^0.10.5",
"easy-pie-chart": "^2.1.7",
"flot": "^0.8.0-alpha",
"flot.dashes": "https://github.com/cquartier/flot.dashes.git",
"font-awesome": "4.7.0",
"formsy-react": "0.19.5",
"fullcalendar": "^3.9.0",
"glyphicons-halflings": "^1.9.1",
"govpredict-morris": "0.5.1",
"jasny-bootstrap": "^3.1.3",
"jquery": "^3.3.1",
"jquery-mapael": "^2.2.0",
"jquery-sparkline": "^2.4.0",
"jquery-ui": "1.12.1",
"jquery.animate-number": "0.0.14",
"jquery.flot-orderBars": "https://github.com/emmerich/flot-orderBars.git",
"jquery.flot.animator": "https://github.com/Codicode/flotanimator.git#3c256c0183d713fd3bf41d04417873928eb1a751",
"jsonwebtoken": "^8.5.1",
"jvectormap": "2.0.4",
"line-awesome": "github:icons8/line-awesome",
"messenger": "git+https://github.com/HubSpot/messenger.git#v1.4.2",
"metrojs": "0.9.77",
"moment": "^2.22.2",
"nvd3": "1.8.6",
"rc-color-picker": "^1.2.6",
"rc-hammerjs": "0.6.9",
"react": "^16.5.2",
"react-animated-number": "^0.4.4",
"react-app-polyfill": "^0.1.3",
"react-autosize-textarea": "^5.0.0",
"react-bootstrap-slider": "^2.1.5",
"react-bootstrap-table": "4.1.5",
"react-datetime": "^2.16.1",
"react-dev-utils": "^6.0.5",
"react-dom": "^16.5.2",
"react-draft-wysiwyg": "1.10.12",
"react-dropzone": "^6.2.4",
"react-flot": "^1.3.0",
"react-google-maps": "^9.4.5",
"react-images": "^0.5.19",
"react-maskedinput": "^4.0.1",
"react-mde": "2.3.4",
"react-redux": "^5.0.7",
"react-router": "^4.3.1",
"react-router-dom": "^4.3.1",
"react-router-hash-link": "^1.2.1",
"react-scrollspy": "^3.3.5",
"react-select2-wrapper": "^1.0.4-beta6",
"react-shuffle": "2.1.0",
"react-slick": "^0.23.1",
"react-sortable-hoc": "^0.8.3",
"react-sortable-tree": "^2.2.0",
"react-sparklines": "^1.7.0",
"react-syntax-highlighter": "^10.1.2",
"react-table": "6.7.6",
"react-tagsinput": "^3.19.0",
"react-toastify": "^5.1.1",
"react-transition-group": "^2.5.2",
"reactstrap": "7.1.0",
"redux": "^4.0.1",
"redux-thunk": "^2.3.0",
"rickshaw": "1.6.6",
"showdown": "1.8.6",
"skycons": "^1.0.0",
"widgster": "^1.0.0"
},
"devDependencies": {
"@babel/core": "7.4.4",
"@babel/plugin-proposal-class-properties": "7.4.4",
"@babel/plugin-proposal-optional-chaining": "^7.2.0",
"@svgr/webpack": "4.2.0",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "10.0.1",
"babel-jest": "24.8.0",
"babel-loader": "8.0.5",
"babel-plugin-named-asset-import": "1.0.0-next.103",
"babel-preset-react-app": "9.0.0",
"bfj": "6.1.1",
"bundle-loader": "0.5.6",
"case-sensitive-paths-webpack-plugin": "2.2.0",
"chalk": "2.4.2",
"css-loader": "2.1.1",
"dotenv": "8.0.0",
"dotenv-expand": "5.1.0",
"eslint": "5.16.0",
"eslint-config-react-app": "4.0.1",
"eslint-loader": "2.1.1",
"eslint-plugin-flowtype": "3.8.1",
"eslint-plugin-import": "2.17.2",
"eslint-plugin-jsx-a11y": "6.2.1",
"eslint-plugin-react": "7.13.0",
"eslint-plugin-react-hooks": "1.6.0",
"expose-loader": "0.7.5",
"file-loader": "3.0.1",
"fs-extra": "7.0.1",
"html-webpack-plugin": "4.0.0-alpha.2",
"identity-obj-proxy": "3.0.0",
"imports-loader": "0.8.0",
"jest": "24.8.0",
"jest-pnp-resolver": "1.2.1",
"jest-resolve": "24.8.0",
"lodash": "4.17.11",
"mini-css-extract-plugin": "0.6.0",
"node-sass": "4.12.0",
"optimize-css-assets-webpack-plugin": "5.0.1",
"pnp-webpack-plugin": "1.4.3",
"postcss-flexbugs-fixes": "4.1.0",
"postcss-loader": "3.0.0",
"postcss-preset-env": "6.6.0",
"postcss-safe-parser": "4.0.1",
"resolve": "1.10.1",
"sass-loader": "7.1.0",
"style-loader": "0.23.0",
"terser-webpack-plugin": "1.2.3",
"url-loader": "1.1.2",
"webpack": "4.31.0",
"webpack-dev-server": "3.3.1",
"webpack-manifest-plugin": "2.0.4",
"webpack-raphael": "2.1.4",
"workbox-webpack-plugin": "4.3.1"
},
"resolutions": {
"jquery": "3.3.1"
}
}
<?php sleep(10) ?>
<h3 class="text-center no-margin animated bounceInDown">Sign up, <del>it's <strong>free</strong></del> and get <strong>$50 now!</strong></h3>
<p class="lead text-muted text-center">
Faith makes it possible to achieve that which man's mind can conceive and believe.
</p>
<form>
<div class="form-group">
<label for="exampleInputEmail1"><i class="fa fa-circle text-warning"></i> &nbsp; Email address</label>
<input type="email" class="form-control input-transparent" id="exampleInputEmail1"
placeholder="Enter email">
</div>
<div class="form-group">
<label for="pswd"><i class="fa fa-circle text-danger"></i> &nbsp; Password</label>
<input class="form-control" id="pswd" type="text" placeholder="Min 8 characters">
</div>
<p>
To make a widget automatically load it's content you just need to set
<strong>data-widgster-autoload</strong> attribute and provide an url.
</p>
<pre><code>data-widgster-load="server/ajax_widget.php"
data-widgster-autoload="true"</code></pre>
<p>
<strong>data-widgster-autoload</strong> may be set to an integer value. If set, for example, to
2000 will refresh widget every 2 seconds.
</p>
<div class="clearfix">
<div class="btn-toolbar float-right">
<button type="submit" class="btn btn-transparent">Cancel</button>
<button type="submit" class="btn btn-success animated wobble">&nbsp;Submit&nbsp;</button>
</div>
</div>
</form>
<!-- demo latetency <?php sleep(2) ?> -->
<p class="text-muted">Simulating latency with tiny php block on the server-side.</p>
<p>A timestamp this widget was created: Apr 24, 19:07:07</p>
<p>A timestamp this widget was updated: <?php echo date("M j, H:i:s") ?></p>
\ No newline at end of file
<!-- <?php sleep(2) //just some delay to simulate latency ?> -->
<ul class="news-list stretchable">
<li class="animated fadeInDown bg-warning-light">
<span class="icon bg-warning text-white">
<i class="fa fa-lock"></i>
</span>
<div class="news-item-info">
<h5 class="name no-margin mb-xs"><a href="#">Just now! Check update time</a></h5>
<p class="fs-mini">
Check this news item timestamp. There is a small server part that generates current timestamp so it
would be easier for you to see ajax widgets in action
</p>
<time class="help-block"><?php echo date("M j, H:i:s")?></time>
</div>
</li>
<li>
<span class="icon bg-danger text-white">
<i class="fa fa-star"></i>
</span>
<div class="news-item-info">
<h5 class="name no-margin mb-xs"><a href="#">First Human Colony on Mars</a></h5>
<p class="fs-mini">
First 700 people will take part in building first human settlement outside of Earth.
That's awesome, right?
</p>
<time class="help-block">Mar 20, 18:46</time>
</div>
</li>
<li>
<span class="icon bg-info text-white">
<i class="fa fa-microphone"></i>
</span>
<div class="news-item-info">
<h5 class="name no-margin mb-xs"><a href="#">Light Blue reached $300</a></h5>
<p class="fs-mini">
Light Blue Inc. shares just hit $300 price. "This was inevitable. It should
have happen sooner or later" - says NYSE expert.
</p>
<time class="help-block">Sep 25, 11:59</time>
</div>
</li>
<li>
<span class="icon bg-success text-white">
<i class="fa fa-eye"></i>
</span>
<div class="news-item-info">
<h5 class="name no-margin mb-xs"><a href="#">No more spying</a></h5>
<p class="fs-mini">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua.
</p>
<time class="help-block">Mar 20, 18:46</time>
</div>
</li>
</ul>
<?php sleep(2) ?>
<div class="list-group list-group-lg">
<a href="#" class="list-group-item animated fadeInDown bg-warning-light">
<span class="thumb-sm mr">
<img class="rounded-circle" src="/images/people/a6.jpg" alt="...">
</span>
<div>
<h6 class="no-margin"><strong>Jenny Wilington</strong></h6>
<small>just now</small>
</div>
<i class="fa fa-circle ml-auto text-success mt-sm"></i>
</a>
<a href="#" class="list-group-item ">
<span class="thumb-sm mr">
<img class="rounded-circle" src="/images/people/a1.jpg" alt="...">
</span>
<div>
<h6 class="m-0">Maikel Basso</h6>
<small class="text-muted">about 2 mins ago</small>
</div>
<i class="fa fa-circle ml-auto text-danger"></i>
</a>
<a href="#" class="list-group-item">
<span class="thumb-sm mr">
<img class="rounded-circle" src="/images/people/a2.jpg" alt="...">
</span>
<div>
<h6 class="m-0">Ianus Arendse</h6>
<small class="text-muted">about 42 mins ago</small>
</div>
<i class="fa fa-circle ml-auto text-info"></i>
</a>
<a href="#" class="list-group-item">
<span class="thumb-sm mr">
<img class="rounded-circle" src="/images/people/a3.jpg" alt="...">
</span>
<div>
<h6 class="m-0">Valdemar Landau</h6>
<small class="text-muted">one hour ago</small>
</div>
<i class="fa fa-circle ml-auto text-success"></i>
</a>
<a href="#" class="list-group-item mb-n-md">
<span class="thumb-sm mr">
<img class="rounded-circle" src="/images/people/a4.jpg" alt="...">
</span>
<div>
<h6 class="m-0">Rick Teagan</h6>
<small class="text-muted">3 hours ago</small>
</div>
<i class="fa fa-circle ml-auto text-warning"></i>
</a>
</div>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.png">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Sing App React Dashboard - Admin Template built with React</title>
<meta name="description" content="React Admin Dashboard Template built with Bootstrap, Redux and React Router by Flatlogic. Over 40 unique pages, hundreds of components and theme support.">
<meta name="keywords" content="react admin, react dashboard, react admin template, react theme, react dashboard template, react dashboard template">
<meta name="author" content="Flatlogic LLC.">
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-36759672-9"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-36759672-9');
</script>
<!-- Yandex.Metrika counter --> <script type="text/javascript" > (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)}; m[i].l=1*new Date();k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)}) (window, document, "script", "https://cdn.jsdelivr.net/npm/yandex-metrica-watch/tag.js", "ym"); ym(48020168, "init", { id:48020168, clickmap:true, trackLinks:true, accurateTrackBounce:true, webvisor:true, trackHash:true, ecommerce:"dataLayer" }); </script> <!-- /Yandex.Metrika counter -->
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
{
"short_name": "Sing App 5.0.0 - Isomorphic React Dashboard",
"name": "Create React App Sample",
"icons": [
{
"src": "/favicon.png",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'production';
process.env.NODE_ENV = 'production';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
const path = require('path');
const chalk = require('chalk');
const fs = require('fs-extra');
const webpack = require('webpack');
const bfj = require('bfj');
const config = require('../config/webpack.config.prod');
const paths = require('../config/paths');
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
const printBuildError = require('react-dev-utils/printBuildError');
const measureFileSizesBeforeBuild =
FileSizeReporter.measureFileSizesBeforeBuild;
const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
const useYarn = fs.existsSync(paths.yarnLockFile);
// These sizes are pretty large. We'll warn for bundles exceeding them.
const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
const isInteractive = process.stdout.isTTY;
// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
process.exit(1);
}
// Process CLI arguments
const argv = process.argv.slice(2);
const writeStatsJson = argv.indexOf('--stats') !== -1;
// We require that you explictly set browsers and do not fall back to
// browserslist defaults.
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
checkBrowsers(paths.appPath, isInteractive)
.then(() => {
// First, read the current file sizes in build directory.
// This lets us display how much they changed later.
return measureFileSizesBeforeBuild(paths.appBuild);
})
.then(previousFileSizes => {
// Remove all content but keep the directory so that
// if you're in it, you don't end up in Trash
fs.emptyDirSync(paths.appBuild);
// Merge with the public folder
copyPublicFolder();
// Start the webpack build
return build(previousFileSizes);
})
.then(
({ stats, previousFileSizes, warnings }) => {
if (warnings.length) {
console.log(chalk.yellow('Compiled with warnings.\n'));
console.log(warnings.join('\n\n'));
console.log(
'\nSearch for the ' +
chalk.underline(chalk.yellow('keywords')) +
' to learn more about each warning.'
);
console.log(
'To ignore, add ' +
chalk.cyan('// eslint-disable-next-line') +
' to the line before.\n'
);
} else {
console.log(chalk.green('Compiled successfully.\n'));
}
console.log('File sizes after gzip:\n');
printFileSizesAfterBuild(
stats,
previousFileSizes,
paths.appBuild,
WARN_AFTER_BUNDLE_GZIP_SIZE,
WARN_AFTER_CHUNK_GZIP_SIZE
);
console.log();
const appPackage = require(paths.appPackageJson);
const publicUrl = paths.publicUrl;
const publicPath = config.output.publicPath;
const buildFolder = path.relative(process.cwd(), paths.appBuild);
printHostingInstructions(
appPackage,
publicUrl,
publicPath,
buildFolder,
useYarn
);
},
err => {
console.log(chalk.red('Failed to compile.\n'));
printBuildError(err);
process.exit(1);
}
)
.catch(err => {
if (err && err.message) {
console.log(err.message);
}
process.exit(1);
});
// Create the production build and print the deployment instructions.
function build(previousFileSizes) {
console.log('Creating an optimized production build...');
let compiler = webpack(config);
return new Promise((resolve, reject) => {
compiler.run((err, stats) => {
let messages;
if (err) {
if (!err.message) {
return reject(err);
}
messages = formatWebpackMessages({
errors: [err.message],
warnings: [],
});
} else {
messages = formatWebpackMessages(
stats.toJson({ all: false, warnings: true, errors: true })
);
}
if (messages.errors.length) {
// Only keep the first error. Others are often indicative
// of the same problem, but confuse the reader with noise.
if (messages.errors.length > 1) {
messages.errors.length = 1;
}
return reject(new Error(messages.errors.join('\n\n')));
}
if (
process.env.CI &&
(typeof process.env.CI !== 'string' ||
process.env.CI.toLowerCase() !== 'false') &&
messages.warnings.length
) {
console.log(
chalk.yellow(
'\nTreating warnings as errors because process.env.CI = true.\n' +
'Most CI servers set it automatically.\n'
)
);
return reject(new Error(messages.warnings.join('\n\n')));
}
const resolveArgs = {
stats,
previousFileSizes,
warnings: messages.warnings,
};
if (writeStatsJson) {
return bfj
.write(paths.appBuild + '/bundle-stats.json', stats.toJson())
.then(() => resolve(resolveArgs))
.catch(error => reject(new Error(error)));
}
return resolve(resolveArgs);
});
});
}
function copyPublicFolder() {
fs.copySync(paths.appPublic, paths.appBuild, {
dereference: true,
filter: file => file !== paths.appHtml,
});
}
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'development';
process.env.NODE_ENV = 'development';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
const fs = require('fs');
const chalk = require('chalk');
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const clearConsole = require('react-dev-utils/clearConsole');
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
const {
choosePort,
createCompiler,
prepareProxy,
prepareUrls,
} = require('react-dev-utils/WebpackDevServerUtils');
const openBrowser = require('react-dev-utils/openBrowser');
const paths = require('../config/paths');
const config = require('../config/webpack.config.dev');
const createDevServerConfig = require('../config/webpackDevServer.config');
const useYarn = fs.existsSync(paths.yarnLockFile);
const isInteractive = process.stdout.isTTY;
// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
process.exit(1);
}
// Tools like Cloud9 rely on this.
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
const HOST = process.env.HOST || '0.0.0.0';
if (process.env.HOST) {
console.log(
chalk.cyan(
`Attempting to bind to HOST environment variable: ${chalk.yellow(
chalk.bold(process.env.HOST)
)}`
)
);
console.log(
`If this was unintentional, check that you haven't mistakenly set it in your shell.`
);
console.log(
`Learn more here: ${chalk.yellow('http://bit.ly/CRA-advanced-config')}`
);
console.log();
}
// We require that you explictly set browsers and do not fall back to
// browserslist defaults.
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
checkBrowsers(paths.appPath, isInteractive)
.then(() => {
// We attempt to use the default port but if it is busy, we offer the user to
// run on a different port. `choosePort()` Promise resolves to the next free port.
return choosePort(HOST, DEFAULT_PORT);
})
.then(port => {
if (port == null) {
// We have not found a port.
return;
}
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const appName = require(paths.appPackageJson).name;
const urls = prepareUrls(protocol, HOST, port);
// Create a webpack compiler that is configured with custom messages.
const compiler = createCompiler(webpack, config, appName, urls, useYarn);
// Load proxy config
const proxySetting = require(paths.appPackageJson).proxy;
const proxyConfig = prepareProxy(proxySetting, paths.appPublic);
// Serve webpack assets generated by the compiler over a web server.
const serverConfig = createDevServerConfig(
proxyConfig,
urls.lanUrlForConfig
);
const devServer = new WebpackDevServer(compiler, serverConfig);
// Launch WebpackDevServer.
devServer.listen(port, HOST, err => {
if (err) {
return console.log(err);
}
if (isInteractive) {
clearConsole();
}
console.log(chalk.cyan('Starting the development server...\n'));
openBrowser(urls.localUrlForBrowser);
});
['SIGINT', 'SIGTERM'].forEach(function(sig) {
process.on(sig, function() {
devServer.close();
process.exit();
});
});
})
.catch(err => {
if (err && err.message) {
console.log(err.message);
}
process.exit(1);
});
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'test';
process.env.NODE_ENV = 'test';
process.env.PUBLIC_URL = '';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
const jest = require('jest');
const execSync = require('child_process').execSync;
let argv = process.argv.slice(2);
function isInGitRepository() {
try {
execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
return true;
} catch (e) {
return false;
}
}
function isInMercurialRepository() {
try {
execSync('hg --cwd . root', { stdio: 'ignore' });
return true;
} catch (e) {
return false;
}
}
// Watch unless on CI, in coverage mode, or explicitly running all tests
if (
!process.env.CI &&
argv.indexOf('--coverage') === -1 &&
argv.indexOf('--watchAll') === -1
) {
// https://github.com/facebook/create-react-app/issues/5210
const hasSourceControl = isInGitRepository() || isInMercurialRepository();
argv.push(hasSourceControl ? '--watch' : '--watchAll');
}
jest.run(argv);
# Action creators
Action Creators should go there
export const DISMISS_ALERT = 'DISMISS_ALERT';
export function dismissAlert(id) {
return {
type: DISMISS_ALERT,
id,
};
}
import axios from 'axios';
export const RECEIVED_DATA_SUCCESS = 'RECEIVED_DATA_SUCCESS';
export const RECEIVING_DATA = 'RECEIVING_DATA';
export function receiveDataRequest() {
return (dispatch) => {
dispatch(receivingData());
axios.get('/analytics').then(res => {
dispatch(receiveDataSuccess(res.data));
})
};
}
export function receiveDataSuccess(payload) {
return {
type: RECEIVED_DATA_SUCCESS,
payload
}
}
export function receivingData() {
return {
type: RECEIVING_DATA
}
}
export const CHANGE_THEME = 'CHANGE_THEME';
export function changeTheme(payload) {
return {
type: CHANGE_THEME,
payload,
};
}
/* eslint-disable import/prefer-default-export */
export const TOGGLE_SIDEBAR = 'TOGGLE_SIDEBAR';
export const OPEN_SIDEBAR = 'OPEN_SIDEBAR';
export const CLOSE_SIDEBAR = 'CLOSE_SIDEBAR';
export const CHANGE_ACTIVE_SIDEBAR_ITEM = 'CHANGE_ACTIVE_SIDEBAR_ITEM';
export function toggleSidebar() {
return {
type: TOGGLE_SIDEBAR,
};
}
export function openSidebar() {
return {
type: OPEN_SIDEBAR,
};
}
export function closeSidebar() {
return {
type: CLOSE_SIDEBAR,
};
}
export function changeActiveSidebarItem(activeItem) {
return {
type: CHANGE_ACTIVE_SIDEBAR_ITEM,
activeItem,
};
}
import axios from 'axios';
import { toast } from 'react-toastify';
export const RECEIVED_PRODUCTS = 'RECEIVED_PRODUCTS';
export const RECEIVING_PRODUCTS = 'RECEIVING_PRODUCTS';
export const RECEIVED_PRODUCT = 'RECEIVED_PRODUCT';
export const RECEIVING_PRODUCT = 'RECEIVING_PRODUCT';
export const UPDATED_PRODUCT = 'UPDATED_PRODUCT';
export const UPDATING_PRODUCT = 'UPDATING_PRODUCT';
export const DELETED_PRODUCT = 'DELETED_PRODUCT';
export const DELETING_PRODUCT = 'DELETING_PRODUCT';
export const RECEIVED_IMAGES = 'RECEIVED_IMAGES';
export function getProductsRequest() {
return (dispatch) => {
dispatch(receivingProducts());
axios.get('/products').then(res => {
dispatch(receiveProducts(res.data));
})
};
}
export function loadProductRequest(id) {
return (dispatch) => {
dispatch(receivingProduct());
axios.get('/products/' + id).then(res => {
dispatch(receiveProduct(res.data));
})
};
}
export function updateProductRequest(product) {
return (dispatch) => {
dispatch(updatingProduct());
axios.put('/products/' + product.id, product).then(res => {
dispatch(updateProduct(res.data));
toast.success("Product has been Updated!");
})
};
}
export function createProductRequest(payload) {
return (dispatch) => {
dispatch(updatingProduct());
axios.post('/products', payload.product).then(res => {
dispatch(updateProduct(res.data));
payload.history.push('/app/ecommerce/management');
toast.success("Product has been Created!");
})
};
}
export function deleteProductRequest(payload) {
return (dispatch) => {
dispatch(deletingProduct(payload));
axios.delete('/products/' + payload.id).then(res => {
dispatch(deleteProduct({id: payload.id}));
if (payload.history.location.pathname !== '/app/ecommerce/management') {
payload.history.push('/app/ecommerce/management');
}
toast.success("Product has been Deleted!");
})
};
}
export function getProductsImagesRequest(payload) {
return (dispatch) => {
axios.get('/products/images-list').then(res => {
dispatch(receiveProductImages(res.data));
if (!payload.img && res.data.length) {
dispatch(updateProduct({id: payload.id, img: res.data[0]}));
}
})
};
}
export function receiveProductImages(payload) {
return {
type: RECEIVED_IMAGES,
payload
}
}
export function receiveProducts(payload) {
return {
type: RECEIVED_PRODUCTS,
payload
}
}
export function receivingProducts() {
return {
type: RECEIVING_PRODUCTS
}
}
export function receiveProduct(payload) {
return {
type: RECEIVED_PRODUCT,
payload
}
}
export function receivingProduct() {
return {
type: RECEIVING_PRODUCT
}
}
export function updateProduct(payload) {
return {
type: UPDATED_PRODUCT,
payload
}
}
export function updatingProduct() {
return {
type: UPDATING_PRODUCT
}
}
export function deleteProduct(payload) {
return {
type: DELETED_PRODUCT,
payload
}
}
export function deletingProduct(payload) {
return {
type: DELETING_PRODUCT,
payload
}
}
import axios from 'axios';
import { toast } from 'react-toastify';
export const REGISTER_REQUEST = 'REGISTER_REQUEST';
export const REGISTER_SUCCESS = 'REGISTER_SUCCESS';
export const REGISTER_FAILURE = 'REGISTER_FAILURE';
function requestRegister() {
return {
type: REGISTER_REQUEST,
};
}
export function receiveRegister() {
return {
type: REGISTER_SUCCESS
};
}
export function registerError(payload) {
return {
type: REGISTER_FAILURE,
payload,
};
}
export function registerUser(payload) {
return (dispatch) => {
dispatch(requestRegister());
debugger;
const creds = payload.creds;
if (creds.email.length > 0 && creds.password.length > 0) {
axios.post("/user/signup", creds).then(res => {
dispatch(receiveRegister());
toast.success("You've been registered successfully");
payload.history.push('/login');
}).catch(err => {
dispatch(registerError(err.response.data));
})
} else {
dispatch(registerError('Something was wrong. Try again'));
}
};
}
import axios from 'axios';
import config from '../config';
import jwt from "jsonwebtoken";
export const LOGIN_REQUEST = 'LOGIN_REQUEST';
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
export const LOGIN_FAILURE = 'LOGIN_FAILURE';
export const LOGOUT_REQUEST = 'LOGOUT_REQUEST';
export const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS';
export const LOGOUT_FAILURE = 'LOGOUT_FAILURE';
function requestLogin() {
return {
type: LOGIN_REQUEST,
};
}
export function receiveLogin() {
return {
type: LOGIN_SUCCESS
};
}
function loginError(payload) {
return {
type: LOGIN_FAILURE,
payload,
};
}
function requestLogout() {
return {
type: LOGOUT_REQUEST,
};
}
export function receiveLogout() {
return {
type: LOGOUT_SUCCESS,
};
}
// Logs the user out
export function logoutUser() {
return (dispatch) => {
dispatch(requestLogout());
localStorage.removeItem('token');
localStorage.removeItem('user');
document.cookie = 'token=;expires=Thu, 01 Jan 1970 00:00:01 GMT;';
axios.defaults.headers.common['Authorization'] = "";
dispatch(receiveLogout());
};
}
export function receiveToken(token) {
return (dispatch) => {
let user = jwt.decode(token).user;
delete user.id;
localStorage.setItem('token', token);
localStorage.setItem('user', JSON.stringify(user));
axios.defaults.headers.common['Authorization'] = "Bearer " + token;
dispatch(receiveLogin());
}
}
export function loginUser(creds) {
return (dispatch) => {
dispatch(requestLogin());
if (creds.social) {
window.location.href = config.baseURLApi + "/user/signin/" + creds.social + (process.env.NODE_ENV === "production" ? "?app=sing-app-react" : "");
}
else if (creds.email.length > 0 && creds.password.length > 0) {
axios.post("/user/signin/local", creds).then(res => {
const token = res.data.token;
dispatch(receiveToken(token));
}).catch(err => {
dispatch(loginError(err.response.data));
})
} else {
dispatch(loginError('Something was wrong. Try again'));
}
};
}
import React from 'react';
import { connect } from 'react-redux';
import { Switch, Route, Redirect } from 'react-router';
import { HashRouter } from 'react-router-dom';
import { ToastContainer } from 'react-toastify';
/* eslint-disable */
import ErrorPage from '../pages/error';
/* eslint-enable */
import '../styles/theme.scss';
import LayoutComponent from '../components/Layout';
import DocumentationLayoutComponent from '../documentation/DocumentationLayout';
import Login from '../pages/login';
import Register from '../pages/register';
import { logoutUser } from '../actions/user';
const PrivateRoute = ({dispatch, component, ...rest }) => {
if (!Login.isAuthenticated(localStorage.getItem('token'))) {
dispatch(logoutUser());
return (<Redirect to="/login"/>)
} else {
return ( // eslint-disable-line
<Route {...rest} render={props => (React.createElement(component, props))}/>
);
}
};
const CloseButton = ({closeToast}) => <i onClick={closeToast} className="la la-close notifications-close"/>
class App extends React.PureComponent {
render() {
return (
<div>
<ToastContainer
autoClose={5000}
hideProgressBar
closeButton={<CloseButton/>}
/>
<HashRouter>
<Switch>
<Route path="/" exact render={() => <Redirect to="/app/main"/>}/>
<Route path="/app" exact render={() => <Redirect to="/app/main"/>}/>
<PrivateRoute path="/app" dispatch={this.props.dispatch} component={LayoutComponent}/>
<Route path="/documentation" exact
render={() => <Redirect to="/documentation/getting-started/overview"/>}/>
<Route path="/documentation" component={DocumentationLayoutComponent}/>
<Route path="/register" exact component={Register}/>
<Route path="/login" exact component={Login}/>
<Route path="/error" exact component={ErrorPage}/>
<Redirect from="*" to="/app/main/analytics"/>
</Switch>
</HashRouter>
</div>
);
}
}
const mapStateToProps = state => ({
isAuthenticated: state.auth.isAuthenticated,
});
export default connect(mapStateToProps)(App);
import React from 'react';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';
import { ListGroup, ListGroupItem, InputGroup, InputGroupAddon, Input, InputGroupText } from 'reactstrap';
import $ from 'jquery';
import * as a1 from '../../images/people/a1.jpg';
import * as a2 from '../../images/people/a2.jpg';
import * as a3 from '../../images/people/a3.jpg';
import * as a4 from '../../images/people/a4.jpg';
import * as a5 from '../../images/people/a5.jpg';
import * as a6 from '../../images/people/a6.jpg';
import * as avatar from '../../images/avatar.png';
import s from './Chat.module.scss';
class Chat extends React.Component {
static propTypes = {
chatOpen: PropTypes.bool,
};
static defaultProps = {
chatOpen: false,
};
constructor(props) {
super(props);
this.handleChangeContacts = this.handleChangeContacts.bind(this);
this.openMessages = this.openMessages.bind(this);
this.filterConversations = this.filterConversations.bind(this);
this.filterMessages = this.filterMessages.bind(this);
this.addMessage = this.addMessage.bind(this);
this.state = {
todayConversations: [{
name: 'Chris Gray',
status: 'success',
lastMessage: 'Hey! What\'s up? So many times since we',
image: a2,
messages: [{
id: 0,
text: 'Hey! What\'s up?',
}, {
id: 1,
text: 'Are you there?',
}, {
id: 2,
text: 'Let me know when you come back.',
}, {
id: 3,
text: 'I am here!',
fromMe: true,
}],
}, {
name: 'Jamey Brownlow',
status: 'gray-light',
lastMessage: 'Good news coming tonight. Seems they agreed to proceed',
image: avatar,
}, {
name: 'Livia Walsh',
status: 'danger',
lastMessage: 'Check out my latest email plz!',
image: a1,
}, {
name: 'Jaron Fitzroy',
status: 'gray-light',
lastMessage: 'What about summer break?',
image: avatar,
}, {
name: 'Mike Lewis',
status: 'success',
lastMessage: 'Just ain\'t sure about the weekend now. 90% I\'ll make it.',
image: a4,
}],
lastWeekConversations: [{
name: 'Freda Edison',
status: 'gray-light',
lastMessage: 'Hey what\'s up? Me and Monica going for a lunch somewhere. Wanna join?',
image: a6,
}, {
name: 'Livia Walsh',
status: 'success',
lastMessage: 'Check out my latest email plz!',
image: a5,
}, {
name: 'Jaron Fitzroy',
status: 'warning',
lastMessage: 'What about summer break?',
image: a3,
}, {
name: 'Mike Lewis',
status: 'gray-light',
lastMessage: 'Just ain\'t sure about the weekend now. 90% I\'ll make it.',
image: avatar,
}],
chatMessageOpened: true,
conversation: Object,
searchValue: '',
};
}
openMessages(conversation, e) {
this.setState({
conversation,
chatMessageOpened: false,
});
$(e.currentTarget).removeClass('active').find('.badge').remove();
}
addMessage(e) {
if (e.key === 'Enter') {
const value = {
text: e.target.value,
fromMe: true,
};
this.setState({
conversation: Object.assign({}, this.state.conversation, {
messages: [
...this.state.conversation.messages || [],
value,
],
}),
});
e.target.value = ''; // eslint-disable-line
}
}
handleChangeContacts(event) {
this.setState({ searchValue: event.target.value });
}
filterConversations(item) {
const isFindName = item.name.toLowerCase()
.indexOf(this.state.searchValue.toLowerCase()) !== -1;
const isFindMessage = item.lastMessage.toLowerCase()
.indexOf(this.state.searchValue.toLowerCase()) !== -1;
return isFindName || isFindMessage;
}
filterMessages(item) {
return item.text.toLowerCase().indexOf(this.state.searchValue.toLowerCase()) !== -1;
}
render() {
return (
<aside className={[s.root, this.props.chatOpen ? s.chatOpen : ''].join(' ')}>
<header className={s.chatHeader}>
<h4 className={s.chatTitle}>Contacts</h4>
<div className="input-group input-group-transparent">
<InputGroup size="sm">
<Input placeholder="Search..." value={this.state.searchValue} onChange={this.handleChangeContacts} />
<InputGroupAddon addonType="append">
<InputGroupText>
<i className="fa fa-search"/>
</InputGroupText>
</InputGroupAddon>
</InputGroup>
</div>
</header>
<div className={[s.chatPanel, s.chatContacts, this.state.chatMessageOpened ? s.chatMessageOpen : ''].join(' ')}>
<h5 className={s.navTitle}>TODAY</h5>
<ListGroup id="chat-sidebar-user-group" className={s.chatSidebarUserGroup}>
{this.state.todayConversations
.filter(this.filterConversations)
.map(item =>
<ListGroupItem
key={item.name}
onClick={e => this.openMessages(item, e)}
>
<i className={['fa fa-circle float-right', `text-${item.status}`].join(' ')} />
<span className="thumb-sm float-left mr">
<img className="rounded-circle" src={item.image} alt="..." />
</span>
<div>
<h6 className={s.messageSender}>{item.name}</h6>
<p className={s.messagePreview}>{item.lastMessage}</p>
</div>
</ListGroupItem>,
)}
</ListGroup>
<h5 className={s.navTitle}>LAST WEEK</h5>
<ListGroup className={s.chatSidebarUserGroup}>
{this.state.lastWeekConversations
.filter(this.filterConversations)
.map(item =>
<ListGroupItem
key={item.name}
onClick={e => this.openMessages(item, e)}
>
<i className={['fa fa-circle float-right', `text-${item.status}`].join(' ')} />
<span className="thumb-sm pull-left mr">
<img className="rounded-circle" src={item.image} alt="..." />
</span>
<div>
<h6 className={s.messageSender}>{item.name}</h6>
<p className={s.messagePreview}>{item.lastMessage}</p>
</div>
</ListGroupItem>,
)}
</ListGroup>
</div>
<div className={[s.chatPanel, s.chatMessages, this.state.chatMessageOpened ? '' : s.chatMessageOpen].join(' ')}>
<h6 className={s.messagesTitle}>
{/* eslint-disable */}
<a onClick={() => this.setState({ chatMessageOpened: true })}>
<i className="fa fa-angle-left mr-xs" />
{this.state.conversation.name}
</a>
{/* eslint-disable */}
</h6>
<ListGroup>
{this.state.conversation.messages &&
this.state.conversation.messages
.filter(this.filterMessages)
.map(item => <ListGroupItem key={item.id} className={[item.fromMe ? s.fromMe : '', s.messageItem]}>
<span className="thumb-sm">
<img className="rounded-circle"
src={item.fromMe ? avatar : this.state.conversation.image} alt="..."/>
</span>
<div className={s.messageBody}>{item.text}</div>
</ListGroupItem>,
)}
</ListGroup>
<footer className={[s.chatFooter, 'form-group'].join(' ')}>
<input className="form-control fs-mini" onKeyPress={this.addMessage} type="text"
placeholder="Type your message"/>
</footer>
</div>
</aside>
);
}
}
export default withRouter(Chat);
@import '../../styles/app';
.root {
position: fixed;
overflow: hidden;
top: 0;
bottom: 0;
right: -$chat-sidebar-width-open;
width: $chat-sidebar-width-open;
border-left: $sidebar-border;
background-color: var(--chat-sidebar-bg-color);
color: #aaa;
transition: right 0.3s ease-in-out;
@include media-breakpoint-down(md) {
right: -($chat-sidebar-width-open + 25px);
width: $chat-sidebar-width-open + 25px;
}
&.chatOpen {
right: 0;
}
.chatHeader {
position: absolute;
width: 100%;
top: 0;
z-index: 3;
padding: 10px;
background-color: var(--chat-sidebar-bg-color);
input {
padding: 0.6rem 0.85rem;
line-height: 1.5;
}
.chatTitle {
margin: 10px;
text-transform: uppercase;
font-size: 15px;
font-weight: 400;
}
}
.chatPanel {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
:global .list-group-item {
border: 0;
padding: 10px 20px;
z-index: 1;
.cirle {
font-size: 11px;
line-height: 37px;
margin-left: auto;
}
}
.navTitle {
margin: 35px 10px 5px 20px;
font-size: 14px;
}
.navTitle:first-child {
margin-top: 0;
}
.messageSender {
text-overflow: ellipsis;
color: var(--sidebar-color);
}
.messagePreview {
margin: 0;
width: 100px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 85%;
color: #999;
}
}
.chatContacts {
padding-top: 105px;
left: -100%;
transition: left 0.2s ease-in-out;
:global .list-group {
margin-top: 10px;
:global .list-group-item {
cursor: pointer;
}
}
&.chatMessageOpen {
left: 0;
overflow-y: auto;
@include scroll-bar(rgba($white, 0.3));
}
}
.chatMessages {
padding-top: 100px;
right: -100%;
transition: right 0.2s ease-in-out;
background-color: var(--sidebar-bg-color);
:global .list-group {
position: absolute;
top: 134px; // header height
bottom: 47px; // footer height
width: 100%;
padding-top: 0.5rem;
overflow-y: auto;
@include scroll-bar(rgba($white, 0.3));
:global .list-group-item {
align-items: flex-start;
}
:global .thumb-sm {
float: left;
}
}
.messageBody {
position: relative;
margin-left: 50px;
padding: 10px;
font-size: 13px;
font-weight: $font-weight-normal;
background-color: $gray-200;
color: $text-color;
border-radius: 0.25rem;
&::before {
right: 100%;
top: 8px;
content: '';
height: 0;
width: 0;
position: absolute;
border: 10px solid rgba(0, 0, 0, 0);
border-right-color: $gray-200;
}
}
.fromMe {
flex-direction: row-reverse;
:global .thumb-sm {
float: right;
}
.messageBody {
margin-left: 0;
margin-right: 50px;
background-color: theme-color('warning');
color: $gray-800;
&::before {
right: auto;
left: 100%;
border-right-color: rgba(0, 0, 0, 0);
border-left-color: theme-color('warning');
}
}
}
.chatFooter {
position: absolute;
z-index: 1;
bottom: 0;
width: 100%;
margin-bottom: 0;
padding: 10px;
background-color: $white;
}
&.chatMessageOpen {
right: 0;
}
.messagesTitle {
margin-bottom: 0;
a {
display: block;
margin-top: -7px;
padding: 17px 16px;
}
}
}
.chatSidebarUserGroup {
:global .list-group-item {
transition: $transition-base;
}
:global .list-group-item.active {
background: rgba($white, 0.1);
}
:global .list-group-item.active h6 {
color: theme-color('warning');
font-weight: $badge-font-weight;
}
:global .list-group-item:hover {
background: var(--sidebar-action-bg);
}
:global .badge {
margin: 8px 5px 0 0;
padding: 3px 5px;
}
:global .fa {
margin-top: 11px;
}
}
.messageItem {
&:hover {
background: transparent;
}
}
}
{
"name": "Chat",
"version": "0.0.0",
"private": true,
"main": "./Chat.js"
}
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router';
import {
Navbar,
Nav,
Dropdown,
NavItem,
NavLink,
Badge,
DropdownToggle,
DropdownMenu,
DropdownItem,
UncontrolledTooltip,
InputGroupAddon,
InputGroup,
Input,
Form,
FormGroup,
} from 'reactstrap';
import $ from 'jquery';
import Notifications from '../Notifications';
import { logoutUser } from '../../actions/user';
import { toggleSidebar, openSidebar, closeSidebar, changeActiveSidebarItem } from '../../actions/navigation';
import a5 from '../../images/people/a5.jpg';
import a6 from '../../images/people/a6.jpg';
import s from './Header.module.scss'; // eslint-disable-line css-modules/no-unused-class
class Header extends React.Component {
static propTypes = {
sidebarOpened: PropTypes.bool.isRequired,
sidebarStatic: PropTypes.bool.isRequired,
chatToggle: PropTypes.func.isRequired,
dispatch: PropTypes.func.isRequired,
location: PropTypes.shape({
pathname: PropTypes.string,
}).isRequired,
};
constructor(props) {
super(props);
this.toggleMenu = this.toggleMenu.bind(this);
this.switchSidebar = this.switchSidebar.bind(this);
this.toggleNotifications = this.toggleNotifications.bind(this);
this.toggleSidebar = this.toggleSidebar.bind(this);
this.doLogout = this.doLogout.bind(this);
this.state = {
menuOpen: false,
notificationsOpen: false,
notificationsTabSelected: 1,
};
}
componentDidMount() {
if (window.innerWidth > 576) {
setTimeout(() => {
const $chatNotification = $('#chat-notification');
$chatNotification.removeClass('hide').addClass('animated fadeIn')
.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', () => {
$chatNotification.removeClass('animated fadeIn');
setTimeout(() => {
$chatNotification.addClass('animated fadeOut')
.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd' +
' oanimationend animationend', () => {
$chatNotification.addClass('hide');
});
}, 6000);
});
$chatNotification.siblings('#toggle-chat')
.append('<i class="chat-notification-sing animated bounceIn"></i>');
}, 4000);
}
$('#search-input').on('blur focus', (e) => {
$('#search-input').parents('.input-group')[e.type === 'focus' ? 'addClass' : 'removeClass']('focus');
});
}
toggleNotifications() {
this.setState({
notificationsOpen: !this.state.notificationsOpen,
});
}
doLogout() {
this.props.dispatch(logoutUser());
}
// collapse/uncolappse
switchSidebar() {
if (this.props.sidebarOpened) {
this.props.dispatch(closeSidebar());
this.props.dispatch(changeActiveSidebarItem(null));
} else {
const paths = this.props.location.pathname.split('/');
paths.pop();
this.props.dispatch(openSidebar());
this.props.dispatch(changeActiveSidebarItem(paths.join('/')));
}
}
// static/non-static
toggleSidebar() {
this.props.dispatch(toggleSidebar());
if (this.props.sidebarStatic) {
localStorage.setItem('staticSidebar', 'false');
this.props.dispatch(changeActiveSidebarItem(null));
} else {
localStorage.setItem('staticSidebar', 'true');
const paths = this.props.location.pathname.split('/');
paths.pop();
this.props.dispatch(changeActiveSidebarItem(paths.join('/')));
}
}
toggleMenu() {
this.setState({
menuOpen: !this.state.menuOpen,
});
}
render() {
const user = JSON.parse(localStorage.getItem('user') || {});
const firstUserLetter = (user.name|| user.email || "P")[0].toUpperCase();
return (
<Navbar className={`${s.root} d-print-none`}>
<Nav>
<NavItem>
<NavLink className="d-md-down-none ml-5" id="toggleSidebar" onClick={this.toggleSidebar}>
<i className="la la-bars" />
</NavLink>
<UncontrolledTooltip placement="bottom" target="toggleSidebar">
Turn on/off<br />sidebar<br />collapsing
</UncontrolledTooltip>
<NavLink className="fs-lg d-lg-none" onClick={this.switchSidebar}>
<span className="rounded rounded-lg bg-gray text-white d-md-none"><i className="la la-bars" /></span>
<i className="la la-bars ml-3 d-sm-down-none" />
</NavLink>
</NavItem>
<NavItem className="d-sm-down-none">
<NavLink className="px-2">
<i className="la la-refresh" />
</NavLink>
</NavItem>
<NavItem className="d-sm-down-none">
<NavLink className="px-2">
<i className="la la-times" />
</NavLink>
</NavItem>
</Nav>
<Form className="d-sm-down-none ml-5" inline>
<FormGroup>
<InputGroup className="input-group-no-border">
<InputGroupAddon addonType="prepend">
<i className="la la-search" />
</InputGroupAddon>
<Input id="search-input" placeholder="Search Dashboard" />
</InputGroup>
</FormGroup>
</Form>
<NavLink className={`${s.navbarBrand} d-md-none`}>
<i className="fa fa-circle text-gray mr-n-sm" />
<i className="fa fa-circle text-warning" />
&nbsp;
sing
&nbsp;
<i className="fa fa-circle text-warning mr-n-sm" />
<i className="fa fa-circle text-gray" />
</NavLink>
<Nav className="ml-auto">
<Dropdown nav isOpen={this.state.notificationsOpen} toggle={this.toggleNotifications} id="basic-nav-dropdown" className={`${s.notificationsMenu} d-sm-down-none`}>
<DropdownToggle nav caret>
<span className={`${s.avatar} rounded-circle thumb-sm float-left mr-2`}>
{user.avatar || user.email === "admin@flatlogic.com" ? (
<img src={user.avatar || a5} alt="..."/>
) : (
<span>{firstUserLetter}</span>
)}
</span>
<span className="small">{user.name || user.email || "Philip smith"}</span>
<span className="ml-1 circle bg-warning text-white fw-bold">13</span>
</DropdownToggle>
<DropdownMenu right className={`${s.notificationsWrapper} py-0 animated animated-fast fadeInUp`}>
<Notifications />
</DropdownMenu>
</Dropdown>
<Dropdown nav isOpen={this.state.menuOpen} toggle={this.toggleMenu} className="d-sm-down-none">
<DropdownToggle nav>
<i className="la la-cog" />
</DropdownToggle>
<DropdownMenu right className="super-colors">
<DropdownItem><i className="la la-user" /> My Account</DropdownItem>
<DropdownItem divider />
<DropdownItem href="/calendar">Calendar</DropdownItem>
<DropdownItem href="/inbox">Inbox &nbsp;&nbsp;<Badge color="danger" pill className="animated bounceIn">9</Badge></DropdownItem>
<DropdownItem divider />
<DropdownItem onClick={this.doLogout}><i className="la la-sign-out" /> Log Out</DropdownItem>
</DropdownMenu>
</Dropdown>
<NavItem>
<NavLink className="d-sm-down-none mr-5" id="toggle-chat" onClick={this.props.chatToggle}>
<i className="la la-globe" />
</NavLink>
<div id="chat-notification" className={`${s.chatNotification} hide `}>
<div className={s.chatNotificationInner}>
<h6 className={`${s.title} d-flex`}>
<span className="thumb-xs">
<img src={a6} alt="" className="rounded-circle mr-xs float-left" />
</span>
Jess Smith
</h6>
<p className={s.text}>Hi there! <br /> This is a completely new version of Sing App <br /> built with <strong className="text-primary">React JS</strong> </p>
</div>
</div>
</NavItem>
<NavItem className="fs-lg d-md-none">
<NavLink href="#" onClick={this.props.chatToggle}>
<span className="rounded rounded-lg bg-gray text-white"><i className="la la-globe" /></span>
</NavLink>
</NavItem>
</Nav>
</Navbar>
);
}
}
function mapStateToProps(store) {
return {
sidebarOpened: store.navigation.sidebarOpened,
sidebarStatic: store.navigation.sidebarStatic,
};
}
export default withRouter(connect(mapStateToProps)(Header));
@import '../../styles/app';
.root {
z-index: 100;
background: var(--navbar-bg);
box-shadow: var(--navbar-shadow);
@include media-breakpoint-down(sm) {
padding: 7px 0;
}
:global {
.input-group {
overflow: hidden;
}
.input-group-prepend {
background-color: #fff;
transition: background-color ease-in-out 0.15s;
border-top-left-radius: 0.3rem;
border-bottom-left-radius: 0.3rem;
display: flex;
justify-content: center;
align-items: center;
width: 35px;
}
.focus .input-group-prepend {
background: #f8f9fa;
}
}
}
.logo {
font-size: 16px;
}
.navbarForm {
padding: 6px 0 6px 1rem;
margin-left: 10px;
display: inline-block;
top: 2px;
width: auto;
.inputAddon {
position: relative;
display: inline;
border: none;
background-color: #fff;
transition: background-color ease-in-out 0.15s;
}
input {
border: none;
padding: 0.6rem 0.85rem 0.6rem 0;
display: inline !important;
width: 250px !important;
top: 2px;
}
}
.chatNotification {
position: absolute;
right: 35px;
top: 50px;
z-index: 20;
margin-top: 3px;
padding: 5px 0;
cursor: pointer;
&::before {
content: ' ';
position: absolute;
top: 0;
right: 18px;
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-bottom: 5px solid $gray-800;
}
.chatNotificationInner {
min-width: 120px;
padding: 8px;
font-size: 12px;
border-radius: 0.25rem;
text-decoration: none;
background-color: $gray-800;
color: #fff;
}
.text {
margin-top: 5px;
margin-bottom: 0;
color: $gray-600;
}
.title {
margin: 0;
font-weight: 600;
line-height: 28px;
font-size: 0.875rem;
span {
margin-right: 7px;
}
}
}
.navbarBrand {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
font-weight: 700;
font-size: 1.25rem;
pointer-events: none;
i {
font-size: 10px;
}
}
.notificationsMenu {
:global .dropdown-menu {
left: auto !important;
right: 0 !important;
top: $navbar-height !important;
}
}
.notificationsWrapper {
width: min-content;
}
.avatar {
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
height: 40px;
width: 40px;
background: $warning;
font-weight: 600;
font-size: 18px;
}
{
"name": "Header",
"version": "0.0.0",
"private": true,
"main": "./Header.js"
}
import React, { Component } from 'react';
import cx from 'classnames';
import { Button } from 'reactstrap';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { DashboardThemes } from '../../reducers/layout';
import { changeTheme } from '../../actions/layout';
import Widget from '../Widget';
import s from './Helper.module.scss'; // eslint-disable-line
import themeDark from '../../images/theme-dark.png';
import themeLight from '../../images/theme-light.png';
class Helper extends Component {
static propTypes = {
dispatch: PropTypes.func.isRequired,
dashboardTheme: PropTypes.string
};
static defaultProps = {
dashboardTheme: DashboardThemes.DARK
};
state = { isOpened: false };
toggle = () => {
this.setState(prevState => ({
isOpened: !prevState.isOpened,
}));
};
changeTheme = (state) => {
this.props.dispatch(changeTheme(state));
};
render() {
const { isOpened } = this.state;
return (
<div className={cx(s.themeHelper, { [s.themeHelperOpened]: isOpened })}>
<Widget
className={s.themeHelperContent}
bodyClass="mt-3"
title={
<header className={cx(s.themeHelperHeader, 'd-flex p-0')}>
<Button color="warning" className={s.themeHelperBtn} onClick={this.toggle}>
<div className={cx(s.themeHelperSpinner, 'text-white')}>
<i className="la la-cog" />
<i className="la la-cog" />
</div>
</Button>
<h6>Theme</h6>
</header>
}
>
<div className={s.themeSwitcher}>
<div className={cx(s.theme, "mb-3")}>
<input checked={this.props.dashboardTheme === DashboardThemes.LIGHT} onClick={() => this.changeTheme(DashboardThemes.LIGHT)} type="radio" id="css-light" value="option2" name="theme-variant" aria-label="Sing Light" readOnly/>
<label htmlFor="css-light">
<img className={s.themeImage} src={themeLight} alt="light theme"/>
</label>
</div>
<div className={s.theme}>
<input checked={this.props.dashboardTheme === DashboardThemes.DARK} onClick={() => this.changeTheme(DashboardThemes.DARK)} type="radio" id="css-dark" value="option1" name="theme-variant" aria-label="Single Dark" readOnly/>
<label htmlFor="css-dark">
<img className={s.themeImage} src={themeDark} alt="dark theme"/>
</label>
</div>
</div>
<div className="mt-4">
<Button
href="https://flatlogic.com/admin-dashboards/sing-app-react"
target="_blank"
className="btn-rounded-f btn-block fs-mini"
color="warning"
>
<span className="text-white">Purchase</span>
</Button>
<Button
href="http://demo.flatlogic.com/sing-app/documentation/"
target="_blank"
className="btn-rounded-f btn-block fs-mini text-white"
>
Documentation
</Button>
</div>
<div className="d-flex justify-content-between mt-lg">
<Button
href="https://flatlogic.com/contact"
target="_blank"
className="btn-outline-default btn-rounded-f fs-mini text-muted px-2"
>
<i className="glyphicon glyphicon-headphones mr-xs" />
Support
</Button>
<Button
href="https://github.com/flatlogic/sing-app"
target="_blank"
className="btn-outline-default btn-rounded-f fs-mini text-muted px-2"
>
<i className="fa fa-github mr-xs" />
Github
</Button>
</div>
<div className="mt-lg d-flex flex-column align-items-center theme-helper__sharing">
<span className="fs-sm">
Thank you for sharing!
</span>
<div className="d-flex justify-content-center text-light mt-2">
<a
target="_blank"
rel="noopener noreferrer"
href="https://twitter.com/intent/tweet?text=Amazing%20dashboard%20built%20with%20NodeJS,%20React%20and%20Bootstrap!&url=https://github.com/flatlogic/react-dashboard&via=flatlogic"
>
<i className="fa fa-twitter pr-1" />
</a>
<a
href="https://www.facebook.com/search/top/?q=flatlogic%20llc"
target="_blank"
rel="noopener noreferrer"
>
<i className="fa fa-facebook pl-1" />
</a>
</div>
</div>
</Widget>
</div>
);
}
}
function mapStateToProps(store) {
return {
dashboardTheme: store.layout.dashboardTheme,
};
}
export default connect(mapStateToProps)(Helper);
@import '../../styles/app';
.themeHelper {
width: $sidebar-width-open;
position: fixed;
right: -$sidebar-width-open;
top: $navbar-height * 1.5;
z-index: 100;
@include transition(right $sidebar-transition-time ease-in-out);
& :global {
.abc-radio-secondary input[type="radio"]:not(:checked)+label::before {
background-color: #798892;
}
.abc-radio-warning input[type="radio"]:not(:checked)+label::before {
background-color: theme-color('warning');
}
}
.themeSwitcher {
display: flex;
flex-direction: column;
align-items: center;
.theme {
position: relative;
&,
& > label {
width: 100%;
height: max-content;
}
& > input {
position: absolute;
width: 0;
height: 0;
padding: 0;
margin: 0;
pointer-events: none;
opacity: 0;
}
& > label {
margin: 0;
border: 1px solid $input-border-color;
padding: 3px;
border-radius: $border-radius;
transition: background-color .2s ease-in-out;
cursor: pointer;
display: block;
&:hover {
background-color: $gray-200;
}
}
& > input:checked + label {
background-color: $gray-300;
}
.themeImage {
width: 100%;
}
}
}
&.themeHelperOpened {
right: 0;
}
.themeHelperBtn {
position: absolute;
width: $sidebar-width-open / 4;
transform: translateX(-76px);
margin-top: -($widget-padding-vertical);
cursor: pointer;
z-index: 200;
border-radius: 50% 0 0 50%;
padding: $spacer * 0.8 $spacer / 2 $spacer * 0.8 $spacer;
&,
&:not(.active) {
box-shadow: $widget-shadow-designated !important;
}
i {
animation-duration: 6500ms;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
i:first-of-type {
animation-name: spin;
margin-right: -$spacer * 1.15;
vertical-align: text-bottom;
}
i:last-of-type {
animation-name: spin-reverse;
vertical-align: $font-size-sm;
}
}
.themeHelperSpinner {
font-size: $font-size-lg * 1.4;
line-height: initial;
}
.themeHelperHeader {
padding-top: 0;
h6 {
margin: auto;
}
}
.themeHelperContent {
box-shadow: $widget-shadow-designated;
border-radius: 0;
}
.themeHelperSharing {
font-size: $font-size-lg;
cursor: pointer;
}
:global .glyphicon {
vertical-align: top;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
50% {
transform: rotate(360deg);
}
}
@keyframes spin-reverse {
0% {
transform: rotate(0deg);
}
50% {
transform: rotate(-360deg);
}
}
}
{
"name": "Helper",
"version": "0.0.0",
"private": true,
"main": "./Helper.js"
}
import React from 'react';
import PropTypes from 'prop-types';
import Formsy from 'formsy-react';
Formsy.addValidationRule('isRange', (values, value, array) => (value >= array[0] && value <= array[1]));
class InputValidation extends React.Component {
/* eslint-disable */
static propTypes = {
trigger: PropTypes.string,
type: PropTypes.string,
className: PropTypes.string,
name: PropTypes.string,
id: PropTypes.string,
placeholder: PropTypes.string,
setValue: PropTypes.func,
isFormSubmitted: PropTypes.func,
getErrorMessage: PropTypes.func,
showRequired: PropTypes.func,
};
/* eslint-enable */
static defaultProps = {
trigger: null,
type: 'text',
className: '',
name: '',
id: '',
placeholder: '',
};
constructor() {
super();
this.changeValue = this.changeValue.bind(this);
}
changeValue(event) {
this.props.setValue(event.currentTarget.value);
}
render() {
const errorMessageObj = (this.props.isFormSubmitted() || this.props.trigger) ? this.props.getErrorMessage() : null;
const required = (this.props.isFormSubmitted() && this.props.showRequired()) ?
<span className={'help-block text-danger'}>This value is required.</span> : null;
const errorMsg = [];
if (errorMessageObj) {
Object.keys(errorMessageObj).forEach((type) => {
errorMsg.push(errorMessageObj[type]);
});
}
const errorList = errorMsg.map((msg, index) =>
<span key={`msg-err-${index.toString()}`} className={'help-block text-danger'}>{msg}</span>,
);
return (
<div className={this.props.className}>
<input
type={this.props.type}
name={this.props.name}
id={this.props.id}
className={'form-control'}
onBlur={this.changeValue}
placeholder={this.props.placeholder}
/>
{required}
{errorList}
</div>
);
}
}
export default Formsy.HOC(InputValidation);
{
"name": "InputValidation",
"version": "0.0.0",
"private": true,
"main": "./InputValidation.js"
}
This diff is collapsed. Click to expand it.
@import '../../styles/app';
.root {
height: 100%;
position: relative;
left: 0;
transition: left $sidebar-transition-time ease-in-out;
&.chatOpen {
left: -($chat-sidebar-width-open);
@include media-breakpoint-down(md) {
left: -($chat-sidebar-width-open + 25px);
}
}
}
.wrap {
position: relative;
min-height: 100vh;
display: flex;
margin-left: 50px;
flex-direction: column;
left: $sidebar-width-open - $sidebar-width-closed;
right: 0;
transition: left $sidebar-transition-time ease-in-out;
@media (max-width: breakpoint-max(sm)) {
margin-left: 0;
left: $sidebar-width-open;
}
}
.sidebarClose div.wrap {
left: 0;
}
.sidebarStatic .wrap {
transition: none;
left: 0;
margin-left: $sidebar-width-open;
}
.content {
position: relative;
flex-grow: 1;
// 20px for footer height
padding: $content-padding $content-padding ($content-padding + 20px);
background-color: $body-bg;
@media (max-width: breakpoint-max(sm)) {
padding: 20px 15px;
}
// hammers disallows text selection, allowing it for large screens
@media (min-width: breakpoint-min(sm)) {
user-select: auto !important;
}
}
.contentFooter {
position: absolute;
bottom: 15px;
color: $text-muted;
}
/* eslint-env mocha */
/* eslint-disable padded-blocks, no-unused-expressions */
import React from 'react';
import { expect } from 'chai';
import { render } from 'enzyme';
import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import App from '../App';
import Layout from './Layout';
const middlewares = [thunk];
const mockStore = configureStore(middlewares);
const initialState = {};
describe('Layout', () => {
it('renders children correctly', () => {
const store = mockStore(initialState);
const wrapper = render(
<App context={{ insertCss: () => {}, store }}>
<Layout>
<div className="child" />
</Layout>
</App>,
);
expect(wrapper.find('div.child').length).to.eq(1);
});
});
{
"name": "Layout",
"version": "0.0.0",
"private": true,
"main": "./Layout.js"
}
import React from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import s from './Loader.module.scss';
class Loader extends React.Component {
static propTypes = {
size: PropTypes.number.isRequired
};
static defaultProps = {
size: 21
};
render() {
return (
<div className={cx(s.root, this.props.className)}>
<i className="la la-spinner la-spin" style={{fontSize: this.props.size}}/>
</div>
);
}
}
export default Loader;
@import "../../styles/app";
.root {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
i {
font-size: 21px;
margin: 0 $spacer;
}
}
\ No newline at end of file
{
"name": "Loader",
"version": "0.0.0",
"private": true,
"main": "./Loader.js"
}
import React from 'react';
import {
ButtonGroup,
Button,
} from 'reactstrap';
import classnames from 'classnames';
import NotificationsDemo from './notifications-demo/Notifications';
import NewNotificationsDemo from './notifications-demo/NewNotifications';
import MessagesDemo from './notifications-demo/Messages';
import ProgressDemo from './notifications-demo/Progress';
import s from './Notifications.module.scss';
class Notifications extends React.Component {
constructor(props) {
super(props);
this.state = {
notificationsTabSelected: 1,
newNotifications: null,
isLoad: false,
};
}
changeNotificationsTab(tab) {
this.setState({
notificationsTabSelected: tab,
newNotifications: null,
});
}
loadNotifications() {
this.setState({
isLoad: true,
});
setTimeout(() => {
this.setState({
newNotifications: (<NewNotificationsDemo />),
isLoad: false,
});
}, 1500);
}
render() {
let notificationsTab;
switch (this.state.notificationsTabSelected) {
case 1:
notificationsTab = (<NotificationsDemo />);
break;
case 2:
notificationsTab = (<MessagesDemo />);
break;
case 3:
notificationsTab = (<ProgressDemo />);
break;
default:
notificationsTab = (<NotificationsDemo />);
break;
}
return (
<section className={`${s.notifications} card navbar-notifications`}>
<header className={[s.cardHeader, 'card-header'].join(' ')}>
<div className="text-center mb-sm">
<strong>You have 13 notifications</strong>
</div>
<ButtonGroup id="notification-buttons">
<Button color="secondary" onClick={() => this.changeNotificationsTab(1)} active={this.state.notificationsTabSelected === 1}>Notifications</Button>
<Button color="secondary" onClick={() => this.changeNotificationsTab(2)} active={this.state.notificationsTabSelected === 2}>Messages</Button>
<Button color="secondary" onClick={() => this.changeNotificationsTab(3)} active={this.state.notificationsTabSelected === 3}>Progress</Button>
</ButtonGroup>
</header>
{this.state.newNotifications || notificationsTab}
<footer className={[s.cardFooter, 'text-sm', 'card-footer'].join(' ')}>
<Button
color="link"
className={classnames({ disabled: this.state.isLoad }, s.btnNotificationsReload, 'btn-xs', 'float-right', 'py-0')}
onClick={() => this.loadNotifications()}
id="load-notifications-btn"
>
{this.state.isLoad ? <span><i className="la la-refresh la-spin" /> Loading...</span> : <i className="la la-refresh" />}
</Button>
<span className="fs-mini">Synced at: 21 Apr 2014 18:36</span>
</footer>
</section>
);
}
}
export default Notifications;
@import '../../styles/app';
.notifications {
@include media-breakpoint-up(md) {
width: 333px;
}
height: 100%;
border: none;
}
.cardHeader {
border-radius: 0;
}
.cardFooter {
padding-top: 14px;
padding-bottom: 14px;
}
.btnNotificationsReload {
color: $navbar-link-color;
outline: none;
i::before {
top: 2px;
}
}
@import '../../../styles/app';
.listGroup {
display: block;
height: 320px;
overflow-y: scroll;
.listGroupItem:first-child {
border: none;
}
}
.listGroupItem {
transition: background-color 0.15s ease-in-out;
text-decoration: none;
color: $gray-700;
border-left: none;
border-right: none;
display: block;
:global .progress {
transition: background 0.15s ease-in-out;
&:hover {
background: $black;
}
}
&:hover {
background-color: $list-group-hover-bg;
:global .progress {
background: $white !important;
}
}
&:first-child {
border-top: none;
border-top-right-radius: 0;
border-top-left-radius: 0;
}
&:last-child {
border-bottom: none;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
}
.notificationIcon {
margin-right: 1rem;
float: left;
@include clearfix;
}
import React from 'react';
import {
ListGroup,
ListGroupItem,
} from 'reactstrap';
import a1 from '../../../images/people/a1.jpg';
import a2 from '../../../images/people/a2.jpg';
import a4 from '../../../images/people/a4.jpg';
import a6 from '../../../images/people/a6.jpg';
import avatar from '../../../images/avatar.png';
import s from './ListGroup.module.scss'; // eslint-disable-line
class MessagesDemo extends React.Component {
render() {
return (
<ListGroup className={[s.listGroup, 'thin-scroll'].join(' ')}>
<ListGroupItem className={[s.listGroupItem, 'bg-warning-light'].join(' ')}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<img className="rounded-circle" src={a2} alt="..." />
<i className="status status-bottom bg-success" />
</span>
<time className="text-link help float-right">10 sec ago</time>
<h6 className="m-0 fw-bold mb-1">Chris Gray</h6>
<p className="deemphasize text-ellipsis m-0">Hey! What&apos;s up? So many times since we</p>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<img className="rounded-circle" src={avatar} alt="..." />
<i className="status status-bottom bg-success" />
</span>
<time className="text-link help float-right">2 min ago</time>
<h6 className="m-0 mb-1">Jamey Brownlow</h6>
<p className="deemphasize text-ellipsis m-0">Good news coming tonight. Seems they agreed to proceed</p>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<img className="rounded-circle" src={a1} alt="..." />
<i className="status status-bottom bg-warning" />
</span>
<time className="text-link help float-right">9 min ago</time>
<h6 className="m-0 mb-1">Livia Walsh</h6>
<p className="deemphasize text-ellipsis m-0">Check out my latest email plz!</p>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<img className="rounded-circle" src={avatar} alt="..." />
<i className="status status-bottom bg-danger" />
</span>
<time className="text-link help float-right">12:56 AM</time>
<h6 className="m-0 mb-1">Jaron Fitzroy</h6>
<p className="deemphasize text-ellipsis m-0">What about summer break?</p>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<img className="rounded-circle" src={a4} alt="..." />
<i className="status status-bottom bg-gray-light" />
</span>
<time className="text-link help float-right">Yesterday</time>
<h6 className="m-0 mb-1">Mike Lewis</h6>
<p className="deemphasize text-ellipsis m-0">Just ain&apos;t sure about the weekend now. 90% I&apos;ll make it.</p>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<img className="rounded-circle" src={a6} alt="..." />
<i className="status status-bottom bg-success" />
</span>
<time className="text-link help float-right">Apr 23</time>
<h6 className="m-0 mb-1">Freda Edison</h6>
<p className="deemphasize text-ellipsis m-0">Hey what&apos;s up? Me and Monica going for a lunch somewhere. Wanna join?</p>
</ListGroupItem>
</ListGroup>
);
}
}
export default MessagesDemo;
import React from 'react';
import {
ListGroup,
ListGroupItem,
Button,
} from 'reactstrap';
import s from './ListGroup.module.scss';
import a3 from '../../../images/people/a3.jpg';
import a5 from '../../../images/people/a5.jpg';
import a6 from '../../../images/people/a6.jpg';
class NewNotificationsDemo extends React.Component {
render() {
return (
<ListGroup className={[s.listGroup, 'thin-scroll'].join(' ')}>
<ListGroupItem className={`${s.listGroupItem} bg-attention`}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<i className="fa fa-check text-success fa-lg" />
</span>
<p className="m-0 overflow-hidden">
2 issues require your approval.
{/* eslint-disable */}
&nbsp;<a href="#">The Search Project</a> completed on time!
{/* eslint-enable */}
<time className="help-block m-0">
just now
</time>
</p>
</ListGroupItem>
<ListGroupItem className={`${s.listGroupItem} bg-attention`}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<img className="rounded-circle" src={a6} alt="..." />
</span>
<p className="m-0 overflow-hidden">
<button className="btn-link">Jeniffer Willington</button>has just endorsed you with 50 points!
<time className="help-block m-0">
30 sec ago
</time>
</p>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<img className="rounded-circle" src={a3} alt="..." />
</span>
<p className="m-0 overflow-hidden">
1 new user just signed up! Check out
{/* eslint-disable */}
&nbsp;<a href="#">Monica Smith</a>'s account.
{/* eslint-enable */}
<time className="help-block m-0">
2 mins ago
</time>
</p>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<i className="glyphicon glyphicon-upload fa-lg" />
</span>
<p className="text-ellipsis m-0">
2.1.0-pre-alpha just released.
<time className="help-block m-0">
5h ago
</time>
</p>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<i className="fa fa-bolt fa-lg" />
</span>
<p className="text-ellipsis m-0 overflow-hidden">
Server load limited.
<time className="help-block m-0">
7h ago
</time>
</p>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<img className="rounded-circle" src={a5} alt="..." />
</span>
<p className="m-0 overflow-hidden">
{/* eslint-disable */}
User <a href="#">Jeff</a> registered
{/* eslint-enable */}
&nbsp;&nbsp;
<Button size="xs" color="success" className="mr-1">Allow</Button>
<Button size="xs" color="danger">Deny</Button>
<time className="help-block m-0">
12:18 AM
</time>
</p>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<i className="fa fa-shield fa-lg" />
</span>
<p className="m-0 overflow-hidden">
{/* eslint-disable */}
Instructions for changing your Envato Account password. Please
check your account <a href="#">security page</a>.
{/* eslint-enable */}
<time className="help-block m-0">
12:18 AM
</time>
</p>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<span className="rounded bg-primary rounded-lg">
<i className="fa fa-facebook text-white" />
</span>
</span>
<p className="text-ellipsis m-0">
New <strong>76</strong> facebook likes received.
<time className="help-block m-0">
15 Apr 2014
</time>
</p>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<span className="circle circle-lg bg-gray-dark">
<i className="fa fa-circle-o text-white" />
</span>
</span>
<p className="text-ellipsis m-0">
Dark matter detected.
<time className="help-block m-0">
15 Apr 2014
</time>
</p>
</ListGroupItem>
</ListGroup>
);
}
}
export default NewNotificationsDemo;
import React from 'react';
import {
ListGroup,
ListGroupItem,
Button,
} from 'reactstrap';
import s from './ListGroup.module.scss';
import a3 from '../../../images/people/a3.jpg';
import a5 from '../../../images/people/a5.jpg';
class NotificationsDemo extends React.Component {
render() {
return (
<ListGroup className={[s.listGroup, 'thin-scroll'].join(' ')}>
<ListGroupItem className={s.listGroupItem}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<img className="rounded-circle" src={a3} alt="..." />
</span>
<p className="m-0 overflow-hidden">
1 new user just signed up! Check out
{/* eslint-disable */}
&nbsp;<a href="#">Monica Smith</a>'s account.
{/* eslint-enable */}
<time className="help-block m-0">
2 mins ago
</time>
</p>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<i className="glyphicon glyphicon-upload fa-lg" />
</span>
<p className="text-ellipsis m-0">
2.1.0-pre-alpha just released.
<time className="help-block m-0">
5h ago
</time>
</p>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<i className="fa fa-bolt fa-lg" />
</span>
<p className="text-ellipsis m-0 overflow-hidden">
Server load limited.
<time className="help-block m-0">
7h ago
</time>
</p>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<img className="rounded-circle" src={a5} alt="..." />
</span>
<p className="m-0 overflow-hidden">
{/* eslint-disable */}
User <a href="#">Jeff</a> registered
{/* eslint-enable */}
&nbsp;&nbsp;
<Button size="xs" color="success" className="mr-1">Allow</Button>
<Button size="xs" color="danger">Deny</Button>
<time className="help-block m-0">
12:18 AM
</time>
</p>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<i className="fa fa-shield fa-lg" />
</span>
<p className="m-0 overflow-hidden">
{/* eslint-disable */}
Instructions for changing your Envato Account password. Please
check your account <a href="#">security page</a>.
{/* eslint-enable */}
<time className="help-block m-0">
12:18 AM
</time>
</p>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<span className="rounded bg-primary rounded-lg">
<i className="fa fa-facebook text-white" />
</span>
</span>
<p className="text-ellipsis m-0">
New <strong>76</strong> facebook likes received.
<time className="help-block m-0">
15 Apr 2014
</time>
</p>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className={[s.notificationIcon, 'thumb-sm'].join(' ')}>
<span className="circle circle-lg bg-gray-dark">
<i className="fa fa-circle-o text-white" />
</span>
</span>
<p className="text-ellipsis m-0">
Dark matter detected.
<time className="help-block m-0">
15 Apr 2014
</time>
</p>
</ListGroupItem>
</ListGroup>
);
}
}
export default NotificationsDemo;
import React from 'react';
import {
ListGroup,
ListGroupItem,
Progress,
UncontrolledTooltip,
} from 'reactstrap';
import s from './ListGroup.module.scss'; // eslint-disable-line
class ProgressDemo extends React.Component {
render() {
return (
<ListGroup className={[s.listGroup, 'thin-scroll'].join(' ')}>
<ListGroupItem className={s.listGroupItem}>
<span className="text-muted float-right">60%</span>
<h6 className="m-0 mb-1 text-gray">
<strong>Urgent:</strong>
&nbsp;Rails 4.1.0 upgrade
</h6>
<Progress className={['m-0'].join(' ')} color="primary" value="60" />
<span className="help-block">3 notes added by James 2h ago...</span>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className="text-muted float-right">83%</span>
<h6 className="m-0 mb-1 text-gray">
<strong>Primary:</strong>
&nbsp;Sing Web App
</h6>
<Progress className={['progress-sm', 'm-0'].join(' ')} color="success" value="83" />
<span className="help-block">verifying stable probability status</span>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className="text-muted float-right">44%</span>
<h6 className="m-0 mb-1">
<span className="circle bg-gray-dark text-warning" id="TooltipQuestion">
<i className="fa fa-question" />
</span>
<UncontrolledTooltip placement="bottom" target="TooltipQuestion">
2 issues require your attention
</UncontrolledTooltip>
&nbsp;
Finish The Road to Hell Song
</h6>
<Progress className={['progress-sm', 'm-0'].join(' ')} color="gray-dark" value="44" />
<span className="help-block">last update: 2h ago</span>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className="text-muted float-right">86%</span>
<h6 className="m-0 mb-1 deemphasize text-gray">
Complete project planning
</h6>
<Progress className={['progress-xs', 'm-0'].join(' ')} color="danger" value="86" />
<span className="help-block">no, no way this is not working...</span>
</ListGroupItem>
<ListGroupItem className={s.listGroupItem}>
<span className="text-muted float-right">100%</span>
<h6 className="m-0 mb-1 deemphasize text-gray">
<strong>Completed:</strong>
&nbsp;Instruct newbies on coding standards
</h6>
<Progress className={['progress-xs', 'm-0'].join(' ')} color="primary" value="100" />
<span className="help-block">last update: April 22, 2014 2:36 pm</span>
</ListGroupItem>
</ListGroup>
);
}
}
export default ProgressDemo;
{
"name": "Notifications",
"version": "0.0.0",
"private": true,
"main": "./Notifications"
}
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { NavLink, withRouter } from 'react-router-dom';
import { Collapse, Badge } from 'reactstrap';
import { Route } from 'react-router';
import classnames from 'classnames';
import s from './LinksGroup.module.scss';
class LinksGroup extends Component {
/* eslint-disable */
static propTypes = {
header: PropTypes.node.isRequired,
link: PropTypes.string.isRequired,
childrenLinks: PropTypes.array,
iconName: PropTypes.string,
className: PropTypes.string,
badge: PropTypes.string,
label: PropTypes.string,
activeItem: PropTypes.string,
isHeader: PropTypes.bool,
index: PropTypes.string,
deep: PropTypes.number,
onActiveSidebarItemChange: PropTypes.func,
labelColor: PropTypes.string,
exact: PropTypes.bool
};
/* eslint-enable */
static defaultProps = {
link: '',
childrenLinks: null,
className: '',
isHeader: false,
deep: 0,
activeItem: '',
label: '',
exact: true
};
constructor(props) {
super(props);
this.togglePanelCollapse = this.togglePanelCollapse.bind(this);
this.state = {
headerLinkWasClicked: true,
};
}
togglePanelCollapse(link) {
this.props.onActiveSidebarItemChange(link);
this.setState({
headerLinkWasClicked: !this.state.headerLinkWasClicked ||
(this.props.activeItem && !this.props.activeItem.includes(this.props.index)),
});
}
render() {
const isOpen = this.props.activeItem &&
this.props.activeItem.includes(this.props.index) &&
this.state.headerLinkWasClicked;
const {exact} = this.props.exact;
if (!this.props.childrenLinks) {
if (this.props.isHeader) {
return (
<li className={classnames('link-wrapper', s.headerLink, this.props.className)}>
<NavLink
to={this.props.link}
activeClassName={s.headerLinkActive}
exact={exact}
target={this.props.target}
>
<span className={classnames('icon', s.icon)}>
<i className={`fi ${this.props.iconName}`} />
</span>
{this.props.header} {this.props.label && <sup className={`${s.headerLabel} text-${this.props.labelColor || 'warning'}`}>{this.props.label}</sup>}
{this.props.badge && <Badge className={s.badge} color="warning" pill>9</Badge>}
</NavLink>
</li>
);
}
return (
<li>
<NavLink
to={this.props.link}
activeClassName={s.headerLinkActive}
style={{ paddingLeft: `${26 + (10 * (this.props.deep - 1))}px` }}
onClick={(e) => {
// able to go to link is not available(for Demo)
if (this.props.link.includes('menu')) {
e.preventDefault();
}
}}
exact={exact}
>
{this.props.header} {this.props.label && <sup className={`${s.headerLabel} text-${this.props.labelColor || 'warning'}`}>{this.props.label}</sup>}
</NavLink>
</li>
);
}
/* eslint-disable */
return (
<Route
path={this.props.link}
children={(params) => {
const { match } = params;
return (
<li className={classnames('link-wrapper', { [s.headerLink]: this.props.isHeader }, this.props.className)}>
<a className={classnames({ [s.headerLinkActive]: match }, { [s.collapsed]: isOpen }, "d-flex")}
style={{ paddingLeft: `${this.props.deep == 0 ? 50 : 26 + 10 * (this.props.deep - 1)}px` }}
onClick={() => this.togglePanelCollapse(this.props.link)}
>
{this.props.isHeader ?
<span className={classnames('icon', s.icon)}>
<i className={`fi ${this.props.iconName}`} />
</span> : null
}
{this.props.header} {this.props.label && <sup className={`${s.headerLabel} text-${this.props.labelColor || 'warning'} ml-1`}>{this.props.label}</sup>}
<b className={['fa fa-angle-left', s.caret].join(' ')} />
</a>
{/* eslint-enable */}
<Collapse className={s.panel} isOpen={isOpen}>
<ul>
{this.props.childrenLinks &&
this.props.childrenLinks.map((child, ind) =>
<LinksGroup
onActiveSidebarItemChange={this.props.onActiveSidebarItemChange}
activeItem={this.props.activeItem}
header={child.header}
link={child.link}
index={child.index}
childrenLinks={child.childrenLinks}
deep={this.props.deep + 1}
key={ind} // eslint-disable-line
/>,
)}
</ul>
</Collapse>
</li>
);
}}
/>
);
}
}
export default withRouter(LinksGroup);
@import '../../../styles/app';
.headerLink {
overflow-x: hidden;
@media (min-width: map_get($grid-breakpoints, lg)) and (min-height: $screen-lg-height), (max-width: map_get($grid-breakpoints, md) - 1px) {
font-size: 13px;
}
a {
display: block;
color: var(--sidebar-color);
text-decoration: none;
cursor: pointer;
&:hover {
text-decoration: none;
color: inherit;
}
}
&:last-child > a {
border-bottom: 1px solid $sidebar-item-border-color;
}
> a {
position: relative;
align-items: center;
padding-left: 50px;
line-height: 35px;
border-top: 1px solid $sidebar-item-border-color;
&:hover {
background-color: var(--sidebar-item-hover-bg-color);
}
> i {
margin-right: 7px;
}
@media (min-width: map_get($grid-breakpoints, lg)) and (min-height: $screen-lg-height), (max-width: map_get($grid-breakpoints, md) - 1px) {
line-height: 55px;
}
}
.icon {
font-size: $font-size-larger;
display: block;
position: absolute;
top: 3px;
left: 11px;
width: 28px;
height: 28px;
line-height: 28px;
text-align: center;
opacity: .7;
@media (min-width: map_get($grid-breakpoints, lg)) and (min-height: $screen-lg-height), (max-width: map_get($grid-breakpoints, md) - 1px) {
top: 12px;
}
}
.badge {
float: right;
line-height: 8px;
margin-top: 9px;
margin-right: 15px;
@media (min-width: map_get($grid-breakpoints, lg)) and (min-height: $screen-lg-height), (max-width: map_get($grid-breakpoints, md) - 1px) {
margin-top: 16px;
}
}
a.headerLinkActive {
color: $sidebar-item-active-color;
font-weight: $font-weight-normal;
&:hover {
color: $sidebar-item-active-color;
}
.icon {
border-radius: 50%;
background-color: $sidebar-item-active-color;
opacity: 1;
i {
color: var(--sidebar-bg-color);
}
}
}
}
.headerLabel {
font-weight: 600;
}
.collapsed .caret {
transform: rotate(-90deg);
}
.caret {
display: flex;
align-items: center;
margin-left: auto;
margin-right: 15px;
@include transition(transform 0.3s ease-in-out);
}
.panel {
border: none;
box-shadow: none;
margin: 0;
border-radius: 0;
background-color: var(--sidebar-panel-bg-color);
a.headerLinkActive {
font-weight: $font-weight-semi-bold;
color: var(--sidebar-color);
&:hover {
color: var(--sidebar-color);
}
}
ul {
background: var(--sidebar-action-bg);
padding: $spacer;
li {
list-style: none;
}
a {
padding: 10px 20px 10px 26px;
font-size: $font-size-mini;
&:hover {
background-color: var(--sidebar-item-hover-bg-color);
}
}
}
}
This diff is collapsed. Click to expand it.
@import '../../styles/app';
.root {
width: $sidebar-width-open;
position: fixed;
left: 0;
top: 0;
bottom: 0;
border-right: $sidebar-border;
background-color: var(--sidebar-bg-color);
color: var(--sidebar-color);
overflow-y: auto;
@include scroll-bar($sidebar-scrollbar-bg);
}
.logo {
margin: 15px 0;
font-size: 18px;
width: 100%;
font-weight: $font-weight-thin;
text-align: center;
transition: width $sidebar-transition-time ease-in-out;
a {
color: var(--logo-color);
padding: 0 5px;
text-decoration: none;
white-space: nowrap;
}
}
.sidebarClose .logo {
width: 50px;
}
.staticSidebar .logo {
width: 100%;
transition: none;
}
.nav {
padding: 30px 0 10px;
overflow-y: auto;
overflow-x: hidden;
}
.navTitle {
margin: 35px 0 5px 11px;
font-size: $font-size-larger;
transition: opacity $sidebar-transition-time ease-in-out;
color: var(--sidebar-nav-title-color);
@media (min-width: breakpoint-min(lg)) {
opacity: 1;
}
}
.sidebarClose .navTitle {
opacity: 0;
}
.staticSidebar .navTitle {
opacity: 1;
transition: none;
}
.actionLink {
color: #aaa;
float: right;
margin-right: 15px;
margin-top: -1px;
}
.labelName {
opacity: 1;
transition: opacity $sidebar-transition-time ease-in-out;
}
.sidebarClose .labelName {
opacity: 0;
}
.staticSidebar .labelName {
transition: none;
opacity: 1;
}
.glyphiconSm {
font-size: 9px;
}
.sidebarLabels {
list-style-type: none;
padding: 11px;
padding-right: 15px;
> li + li {
margin-top: 10px;
}
li > a {
font-size: $font-size-mini;
color: var(--sidebar-color);
text-decoration: none;
> i {
font-size: 11px;
vertical-align: 1px;
transition: margin-left $sidebar-transition-time ease-in-out;
}
}
}
.sidebarClose {
.sidebarLabels > li > a > i {
margin-left: 8px;
transition: margin-left $sidebar-transition-time ease-in-out;
}
}
.staticSidebar {
.sidebarLabels > li > a > i {
transition: none;
margin-left: 0;
}
}
.sidebarAlerts {
margin-bottom: $spacer * 2;
transition: opacity $sidebar-transition-time ease-in-out;
opacity: 1;
}
.sidebarClose .sidebarAlerts {
opacity: 0;
}
.staticSidebar .sidebarAlerts {
opacity: 1;
transition: none;
}
.sidebarAlert {
background: transparent;
margin-bottom: 0;
padding: 0.5rem 11px;
padding-right: 15px;
}
.sidebarProgress {
background-color: var(--sidebar-progress-bg-color);
}
.groupTitle {
margin-bottom: 15px;
}
{
"name": "Sidebar",
"version": "0.0.0",
"private": true,
"main": "./Sidebar.js"
}
import React from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
const Skycons = require('skycons')(window || {});
class Skycon extends React.Component {
static propTypes = {
color: PropTypes.string.isRequired,
autoPlay: PropTypes.bool,
icon: PropTypes.oneOf([ // eslint-disable-line
'CLEAR_DAY',
'CLEAR_NIGHT',
'PARTLY_CLOUDY_DAY',
'PARTLY_CLOUDY_NIGHT',
'CLOUDY',
'RAIN',
'SLEET',
'SNOW',
'WIND',
'FOG',
]),
width: PropTypes.string.isRequired,
height: PropTypes.string.isRequired,
};
static defaultProps = {
color: null,
autoPlay: true,
width: '100%',
height: '100%',
};
constructor(props) {
super(props);
this.state = {
skycons: new Skycons({ color: this.props.color }),
};
}
componentDidMount() {
const { skycons } = this.state;
skycons.add(ReactDOM.findDOMNode(this), Skycons[this.props.icon]); // eslint-disable-line
if (this.props.autoPlay) {
skycons.play();
}
}
componentWillReceiveProps(nextProps) {
this.state.skycons.set(ReactDOM.findDOMNode(this), Skycons[nextProps.icon]); // eslint-disable-line
}
play() {
this.state.skycons.play();
}
pause() {
this.state.skycons.pause();
}
render() {
const {
...restPops
} = this.props;
return (
<canvas width={this.props.width} height={this.props.height} {...restPops} />
);
}
}
export default Skycon;
{
"name": "Skycons",
"version": "0.0.0",
"private": true,
"main": "./Skycons.js"
}
import React from 'react';
import $ from 'jquery';
import PropTypes from 'prop-types';
/* eslint-disable */
import 'imports-loader?jQuery=jquery,this=>window!jquery-sparkline';
/* eslint-enable */
class Sparklines extends React.Component {
static propTypes = {
data: PropTypes.arrayOf(
PropTypes.arrayOf(PropTypes.number),
),
options: PropTypes.oneOfType([
PropTypes.arrayOf(
PropTypes.shape({
type: PropTypes.string.isRequired,
}),
),
PropTypes.shape({
type: PropTypes.string.isRequired,
}),
]),
};
static defaultProps = {
data: [],
options: {},
};
componentDidMount() {
this.initSparkline();
}
initSparkline() {
const $el = $(this.sparklineRef);
const model = $.type(this.data) === 'string' ?
this.props.data.replace(/(^,)|(,$)/g, '')
: this.props.data;
const options = this.props.options;
if ($.type(model) === 'array' && $.type(options) === 'array') {
options.forEach((singleOptions, i) => {
if (i === 0) {
$el.sparkline(model[i], singleOptions);
} else { // set composite for next calls
$el.sparkline(model[i], $.extend({ composite: true }, singleOptions));
}
});
} else {
const data = $.type(model) === 'array' ? model : model.split(',');
$el.sparkline(data, options);
}
}
render() {
return (
<div
className="sparkline" ref={(r) => {
this.sparklineRef = r;
}}
/>
);
}
}
export default Sparklines;
{
"name": "Sparklines",
"version": "0.0.0",
"private": true,
"main": "./Sparklines.js"
}
import React from 'react';
import PropTypes from 'prop-types';
import jQuery from 'jquery';
import { UncontrolledTooltip } from 'reactstrap';
import 'imports-loader?window.jQuery=jquery,this=>window!widgster'; // eslint-disable-line
import s from './Widget.module.scss';
import Loader from '../Loader'; // eslint-disable-line css-modules/no-unused-class
class Widget extends React.Component {
static propTypes = {
title: PropTypes.node,
className: PropTypes.string,
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]),
close: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
fullscreen: PropTypes.bool,
collapse: PropTypes.bool,
refresh: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
settings: PropTypes.bool,
settingsInverse: PropTypes.bool,
tooltipPlacement: PropTypes.string,
showTooltip: PropTypes.bool,
bodyClass: PropTypes.string,
customControls: PropTypes.node,
options: PropTypes.object, //eslint-disable-line,
fetchingData: PropTypes.bool
};
static defaultProps = {
title: null,
className: '',
children: [],
close: false,
fullscreen: false,
collapse: false,
refresh: false,
settings: false,
settingsInverse: false,
tooltipPlacement: 'bottom',
showTooltip: false,
bodyClass: '',
customControls: null,
options: {},
fetchingData: false
};
constructor(prop) {
super(prop);
this.state = {
randomId: Math.floor(Math.random() * 100),
};
}
componentDidMount() {
const options = this.props.options;
options.bodySelector = '.widget-body';
jQuery(this.el).widgster(options);
}
render() {
const {
title,
className,
children,
close,
fullscreen,
collapse,
refresh,
settings,
settingsInverse,
tooltipPlacement,
showTooltip,
bodyClass,
customControls,
fetchingData,
options, //eslint-disable-line
...attributes
} = this.props;
const randomId = this.state.randomId;
const mainControls = !!(close || fullscreen || collapse || refresh || settings || settingsInverse);
return (
<section
className={['widget', s.widget, className].join(' ')}
ref={(widget) => { this.el = widget; }} {...attributes}
>
{
title && (
typeof title === 'string'
? <h5 className={s.title}>{title}</h5>
: <header className={s.title}>{title}</header>
)
}
{
!customControls && mainControls && (
<div className={`${s.widgetControls} widget-controls`}>
{settings && (
<button><i className="la la-cog" /></button>
)}
{settingsInverse && (
<button className={`bg-gray-transparent ${s.inverse}`}><i
className="la la-cog text-white"
/></button>
)}
{refresh && (
<button data-widgster="load" id={`reloadId-${randomId}`}>
{typeof refresh === 'string' ?
<strong className="text-gray-light">{refresh}</strong> :
<i className="la la-refresh" />}
{showTooltip && (
<UncontrolledTooltip
placement={tooltipPlacement}
target={`reloadId-${randomId}`}
>Reload</UncontrolledTooltip>
)}
</button>
)}
{fullscreen && (
<button data-widgster="fullscreen" id={`fullscreenId-${randomId}`}>
<i className="glyphicon glyphicon-resize-full" />
{showTooltip && (
<UncontrolledTooltip
placement={tooltipPlacement}
target={`fullscreenId-${randomId}`}
>Fullscreen</UncontrolledTooltip>
)}
</button>
)}
{fullscreen && (
<button data-widgster="restore" id={`restoreId-${randomId}`}>
<i className="glyphicon glyphicon-resize-small" />
{showTooltip && (
<UncontrolledTooltip
placement={tooltipPlacement}
target={`restoreId-${randomId}`}
>Restore</UncontrolledTooltip>
)}
</button>
)}
{collapse && (
<span>
<button data-widgster="collapse" id={`collapseId-${randomId}`}>
<i className="la la-angle-down" />
{showTooltip && (
<UncontrolledTooltip
placement={tooltipPlacement}
target={`collapseId-${randomId}`}
>Collapse</UncontrolledTooltip>
)}
</button>
</span>
)}
{collapse && (
<span>
<button data-widgster="expand" id={`expandId-${randomId}`}>
<i className="la la-angle-up" />
{showTooltip && (
<UncontrolledTooltip
placement={tooltipPlacement}
target={`expandId-${randomId}`}
>Expand</UncontrolledTooltip>
)}
</button>
</span>
)}
{close && (
<button data-widgster="close" id={`closeId-${randomId}`}>
{typeof close === 'string' ?
<strong className="text-gray-light">{close}</strong> :
<i className="la la-remove" />}
{showTooltip && (
<UncontrolledTooltip
placement={tooltipPlacement}
target={`closeId-${randomId}`}
>Close</UncontrolledTooltip>
)}
</button>
)}
</div>
)}
{
customControls && (
<div className={`${s.widgetControls} widget-controls`}>
{customControls}
</div>
)
}
<div className={`${s.widgetBody} widget-body ${bodyClass}`}>
{fetchingData ? <Loader className={s.widgetLoader} size={40}/> : children}
</div>
</section>
);
}
}
export default Widget;
@import '../../styles/app';
.title {
margin-top: 0;
color: $widget-title-color;
@include clearfix();
}
:global .widget.collapsed {
min-height: unset;
}
.widget {
display: block;
position: relative;
margin-bottom: $grid-gutter-width;
padding: $widget-padding-vertical $widget-padding-horizontal;
background: $widget-bg-color;
border-radius: $widget-border-radius;
box-shadow: var(--widget-shadow);
min-height: 150px;
> header {
margin: (-$widget-padding-vertical) (-$widget-padding-horizontal);
padding: $widget-padding-vertical $widget-padding-horizontal;
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
}
}
:global {
.loader {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
.spinner {
position: absolute;
top: 50%;
width: 100%; //ie fix
margin-top: -10px;
font-size: 20px;
text-align: center;
}
}
.widget-body.p-0 {
margin: $widget-padding-vertical (-$widget-padding-horizontal) (-$widget-padding-vertical);
+ footer {
margin-top: $widget-padding-vertical;
}
}
}
&:global.bg-transparent {
box-shadow: none;
}
}
.widgetBody {
@include clearfix();
> footer {
margin: $spacer/2 (-$widget-padding-horizontal) (-$widget-padding-vertical);
padding: 10px 20px;
}
}
.widgetControls + .widgetBody {
margin-top: $widget-padding-vertical;
}
.widgetControls,
:global(.widget-controls) {
position: absolute;
z-index: 1;
top: 0;
right: 0;
padding: 14px;
font-size: $font-size-sm;
button {
padding: 1px 4px;
border-radius: 4px;
color: rgba($black, 0.4);
background: transparent;
border: none;
@include transition(color 0.15s ease-in-out);
&:hover {
color: rgba($black, 0.1);
text-decoration: none;
}
&:active,
&:focus {
outline: none;
}
:global {
.la {
position: relative;
top: 2px;
}
.glyphicon {
font-size: 0.7rem;
}
}
}
}
.inverse {
top: 2px;
position: relative;
margin-left: 3px;
:global {
.glyphicon {
vertical-align: baseline;
}
}
}
:global {
.widget-image {
position: relative;
overflow: hidden;
margin: (-$widget-padding-vertical) (-$widget-padding-horizontal);
border-radius: $border-radius;
> img {
max-width: 100%;
border-radius: $border-radius $border-radius 0 0;
transition: transform 0.15s ease;
}
&:hover > img {
transform: scale(1.1, 1.1);
}
.title {
position: absolute;
top: 0;
left: 0;
margin: 20px;
}
.info {
position: absolute;
top: 0;
right: 0;
margin: 20px;
}
}
.widget-footer-bottom {
position: absolute;
bottom: 0;
width: 100%;
}
.widget-sm {
height: 230px;
}
.widget-md {
height: 373px;
}
.widget-padding-md {
padding: $widget-padding-vertical $widget-padding-horizontal;
}
.widget-padding-lg {
padding: $widget-padding-vertical*2 $widget-padding-horizontal*2;
}
.widget-body-container {
position: relative;
height: 100%;
}
.widget-top-overflow,
.widget-middle-overflow {
position: relative;
margin: 0 (-$widget-padding-horizontal);
> img {
max-width: 100%;
}
}
.widget-top-overflow {
margin-top: (-$widget-padding-vertical);
border-top-left-radius: $border-radius;
border-top-right-radius: $border-radius;
overflow: hidden;
> img {
border-top-left-radius: $border-radius;
border-top-right-radius: $border-radius;
}
> .btn-toolbar {
position: absolute;
top: 0;
right: 0;
z-index: 1;
margin-right: $widget-padding-horizontal;
@include media-breakpoint-up(md) {
top: auto;
bottom: 0;
}
}
}
.widget-icon {
opacity: 0.5;
font-size: 42px;
height: 60px;
line-height: 45px;
display: inline-block;
}
}
.widgetLoader {
position: absolute;
top: 0;
left: 0;
}
{
"name": "Widget",
"version": "0.0.0",
"private": true,
"main": "./Widget.js"
}
const hostApi = process.env.NODE_ENV === "development" ? "http://localhost" : "https://flatlogic-node-backend.herokuapp.com";
const portApi = process.env.NODE_ENV === "development" ? 8080 : "";
const baseURLApi = `${hostApi}${portApi ? `:${portApi}` : ``}`;
export default {
hostApi,
portApi,
baseURLApi
};
\ No newline at end of file
import React, { Component } from 'react';
import PropTypes from 'prop-types';
class Bundle extends Component {
static propTypes = {
load: PropTypes.func.isRequired,
children: PropTypes.func.isRequired,
};
static generateBundle = loadModule => () => (
/* eslint-disable */
<Bundle load={loadModule}>
{Mod => Mod ? <Mod /> : <div style={{ textAlign: 'center', paddingTop: '35vh' }}>Loading</div>}
</Bundle>
/* eslint-enable */
);
state = {
// short for "module" but that's a keyword in js, so "mod"
mod: null,
};
componentWillMount() {
this.load(this.props);
}
componentWillReceiveProps(nextProps) {
if (nextProps.load !== this.props.load) {
this.load(nextProps);
}
}
load(props) {
this.setState({
mod: null,
});
props.load((mod) => {
this.setState({
// handle both es imports and cjs
mod: mod.default ? mod.default : mod,
});
});
}
render() {
return this.props.children(this.state.mod);
}
}
export default Bundle;
const config = {
name: 'sing',
title: 'Sing Dashboard App built with React JS by Flatlogic',
version: '3.8.0',
settings: {
screens: {
'xs-max': 543,
'sm-min': 544,
'sm-max': 767,
'md-min': 768,
'md-max': 991,
'lg-min': 992,
'lg-max': 1199,
'xl-min': 1200,
},
navCollapseTimeout: 2500,
},
};
export default function isScreen(size) {
const screenPx = window.innerWidth;
return (screenPx >= config.settings.screens[`${size}-min`] || size === 'xs')
&& (screenPx <= config.settings.screens[`${size}-max`] || size === 'xl');
}
import React, { Component } from 'react';
import hoistStatics from 'hoist-non-react-statics';
import { updateMeta } from '../DOMUtils';
import { defaultMeta } from '../config';
function withMeta(ComposedComponent) {
class WithMeta extends Component {
componentWillMount() {
if (ComposedComponent.meta) {
Object.keys(ComposedComponent.meta).forEach((metaKey) => {
if (metaKey === 'title') {
document.title = `${ComposedComponent.meta[metaKey]} - ${defaultMeta[metaKey]}`;
return;
}
updateMeta(metaKey, ComposedComponent.meta[metaKey]);
});
}
}
componentWillUnmount() {
Object.keys(defaultMeta).forEach((metaKey) => {
if (metaKey === 'title') {
document.title = defaultMeta[metaKey];
return;
}
updateMeta(metaKey, defaultMeta[metaKey]);
});
}
render() {
return <ComposedComponent {...this.props} />;
}
}
WithMeta.ComposedComponent = ComposedComponent;
return hoistStatics(WithMeta, ComposedComponent);
}
export default withMeta;
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { Link } from 'react-router-dom';
import { withRouter } from 'react-router';
import {
Navbar,
Nav,
NavItem,
NavLink,
} from 'reactstrap';
import { openSidebar, closeSidebar, changeActiveSidebarItem } from '../actions/navigation';
import s from '../components/Header/Header.module.scss'; // eslint-disable-line css-modules/no-unused-class
import sd from './styles.module.scss';
import twitterLogo from '../images/documentation/twitter-logo.svg';
import dribbleLogo from '../images/documentation/dribble-logo.svg';
import facebookLogo from '../images/documentation/facebook-logo.svg';
import instagramLogo from '../images/documentation/instagram-logo.svg';
import linkedinLogo from '../images/documentation/linkedin-logo.svg';
import githubLogo from '../images/documentation/github-logo.svg';
class Header extends React.Component {
static propTypes = {
sidebarOpened: PropTypes.bool.isRequired,
sidebarStatic: PropTypes.bool.isRequired,
chatToggle: PropTypes.func.isRequired,
dispatch: PropTypes.func.isRequired,
location: PropTypes.shape({
pathname: PropTypes.string,
}).isRequired,
};
constructor(props) {
super(props);
this.toggleMenu = this.toggleMenu.bind(this);
this.switchSidebar = this.switchSidebar.bind(this);
this.state = {
menuOpen: false,
notificationsOpen: false,
notificationsTabSelected: 1,
};
}
// collapse/uncolappse
switchSidebar() {
if (this.props.sidebarOpened) {
this.props.dispatch(closeSidebar());
this.props.dispatch(changeActiveSidebarItem(null));
} else {
const paths = this.props.location.pathname.split('/');
paths.pop();
this.props.dispatch(openSidebar());
this.props.dispatch(changeActiveSidebarItem(paths.join('/')));
}
}
toggleMenu() {
this.setState({
menuOpen: !this.state.menuOpen,
});
}
render() {
return (
<Navbar className={classnames(s.root, sd.header, 'd-print-none')}>
<div className="container">
<div className="row w-100 d-flex align-items-center">
<Nav>
<NavItem>
<NavLink className="fs-lg d-lg-none d-md-none" onClick={this.switchSidebar}>
<span className="rounded rounded-lg text-white d-md-none"><i className="la la-bars" /></span>
<i className="la la-bars ml-3 d-sm-down-none" />
</NavLink>
</NavItem>
<NavItem>
<NavLink className={classnames(s.logo, 'd-sm-down-none px-4')} href={'/documentation'}>
<span className={'fw-semi-bold'}>Sing App React</span> &nbsp; Documentation
</NavLink>
</NavItem>
</Nav>
<NavLink className={`${s.navbarBrand} d-md-none text-muted`}>
<i className="fa fa-circle text-gray mr-n-sm" />
<i className="fa fa-circle text-warning" />
&nbsp;
documentation
&nbsp;
<i className="fa fa-circle text-warning mr-n-sm" />
<i className="fa fa-circle text-muted" />
</NavLink>
<Nav className="ml-auto">
<NavItem className="d-flex alight-items-center d-md-down-none">
<NavLink href="https://twitter.com/flatlogic" className="mr-1">
<img src={twitterLogo} alt="twitter" />
</NavLink>
<NavLink href="https://dribbble.com/flatlogic" className="mr-1">
<img src={dribbleLogo} alt="dribble" />
</NavLink>
<NavLink href="https://dribbble.com/flatlogic" className="mr-1">
<img src={facebookLogo} alt="facebook" />
</NavLink>
<NavLink href="https://instagram.com/flatlogiccom/" className="mr-1">
<img src={instagramLogo} alt="instagram" />
</NavLink>
<NavLink href="https://www.linkedin.com/company/flatlogic/" className="mr-1">
<img src={linkedinLogo} alt="linkedin" />
</NavLink>
<NavLink href="https://github.com/flatlogic" className="mr-3">
<img src={githubLogo} alt="github" />
</NavLink>
</NavItem>
<NavItem className="d-flex align-items-center">
<NavItem className="d-md-down-none">
<Link to="/" className="btn btn-default">
Live Preview
</Link>
</NavItem>
<NavLink href="https://flatlogic.com/admin-dashboards/sing-app-react" target="_blank" className="mr-1">
<button className="btn btn-warning text-gray fw-semi-bold">
Buy Now
</button>
</NavLink>
</NavItem>
</Nav>
</div>
</div>
</Navbar>
);
}
}
function mapStateToProps(store) {
return {
sidebarOpened: store.navigation.sidebarOpened,
sidebarStatic: store.navigation.sidebarStatic,
};
}
export default withRouter(connect(mapStateToProps)(Header));
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
No preview for this file type
This diff could not be displayed because it is too large.
No preview for this file type
No preview for this file type
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.