Woojin Lee

Add react dashboard template

Showing 143 changed files with 5106 additions and 0 deletions
This diff could not be displayed because it is too large.
{
"name": "khubox",
"author": "2020-1_KHU_CloudComputing_E",
"email": "16wjlee@khu.ac.kr",
"licence": "MIT",
"version": "0.3.0",
"private": false,
"scripts": {
"start": "react-s`cripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"dependencies": {
"@material-ui/core": "^4.2.1",
"@material-ui/icons": "^4.2.1",
"@material-ui/styles": "^4.2.1",
"chart.js": "^2.8.0",
"clsx": "^1.0.4",
"history": "^4.9.0",
"moment": "^2.24.0",
"node-sass": "^4.12.0",
"prop-types": "^15.7.2",
"react": "^16.8.6",
"react-chartjs-2": "^2.7.6",
"react-dom": "^16.8.6",
"react-perfect-scrollbar": "^1.5.3",
"react-router-dom": "^5.0.1",
"react-scripts": "^3.0.1",
"recompose": "^0.30.0",
"underscore": "^1.9.1",
"uuid": "^3.3.2",
"validate.js": "^0.13.1"
},
"devDependencies": {
"eslint": "5.16.0",
"eslint-plugin-prettier": "^3.0.1",
"eslint-plugin-react": "^7.12.4",
"prettier": "^1.17.1",
"prettier-eslint": "^8.8.2",
"prettier-eslint-cli": "^4.7.1",
"typescript": "^3.5.1"
}
}
/* /index.html 200
\ No newline at end of file
No preview for this file type
<svg width="133" height="36" viewBox="0 0 133 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 2">
<g id="flex">
<path id="Combined Shape" fill-rule="evenodd" clip-rule="evenodd" d="M0 18.1065C0 27.9411 8.05887 36 18.1065 36C27.9411 36 36 27.9411 36 18.1065C36 8.05887 27.9411 0 18.1065 0C8.05887 0 0 8.05887 0 18.1065ZM33.7263 18.1065C33.7263 26.6854 26.6854 33.7263 18.1065 33.7263C9.34353 33.7263 2.27368 26.714 2.27368 18.1065C2.27368 9.3146 9.3146 2.27368 18.1065 2.27368C26.714 2.27368 33.7263 9.34353 33.7263 18.1065Z" fill="white"/>
<path id="Oval 3" fill-rule="evenodd" clip-rule="evenodd" d="M16.4288 13.5917C16.7107 13.359 17.0649 13.2318 17.4305 13.2318C17.7922 13.2318 18.1429 13.3564 18.4235 13.5846L22.6335 17.0082C23.0074 17.3123 23.5156 17.3923 23.9648 17.218L25.9502 16.4474C26.1292 16.3779 26.3302 16.4036 26.4851 16.517C27.0788 16.9516 28.5751 18.0497 29.1289 18.482C30.4861 19.5416 31.486 20.25 31.486 20.25C31.486 20.25 31.4686 19.8601 31.486 19.4401C31.846 10.718 25.2324 4.39017 17.8022 4.50144C10.3803 4.61568 4.38132 10.5662 4.50178 18.8354C4.51309 19.5319 4.6193 20.25 4.6193 20.25L6.50953 18.8354L8.80622 17.1806C9.12242 16.9528 9.54513 16.9393 9.87525 17.1464L10.7991 17.7261C11.0088 17.8577 11.2793 17.8402 11.4703 17.6826L16.4288 13.5917Z" fill="white"/>
<path id="Oval 4" fill-rule="evenodd" clip-rule="evenodd" d="M16.6359 34.7904C18.8195 35.0437 20.6187 34.6644 21.2437 34.486C21.5288 34.4046 22.5941 34.144 22.8452 34.0596C23.6863 33.777 24.9699 33.1782 25.7013 32.7418C26.7957 32.0887 27.5685 31.4007 28.6388 30.4354C31.015 28.2924 32.625 24.3249 32.625 23.92C32.625 23.8287 28.2146 20.5068 26.9191 19.5329C26.7151 19.3796 26.4318 19.4032 26.253 19.5853C26.0843 19.7571 26.0583 20.0226 26.1911 20.2234C26.6343 20.894 27.5743 22.3246 27.6195 22.4617C27.792 22.9849 27.5465 23.2804 27.3009 23.1231C27.0553 22.9658 21.5646 19.2672 21.5646 19.2672L18.2802 16.9963C17.8686 16.7117 17.3068 17.0063 17.3068 17.5066C17.3068 17.5066 17.1957 19.1166 17.1957 20.1676C17.1957 20.5941 17.1518 21.1118 16.6359 21.246C16.3774 21.3132 15.7234 21.3527 15.7234 21.3527L10.1751 20.9334C9.79851 20.905 9.58736 21.358 9.85128 21.6281C9.85128 21.6281 17.1957 26.5849 17.1957 26.9884C17.1957 27.846 14.552 26.4718 12.4773 25.4639C9.95208 24.2372 7.14641 23.1341 6.44734 22.8633C6.34242 22.8227 6.22787 22.8316 6.13033 22.8877C5.52897 23.2335 3.35694 24.4869 3.37515 24.5407C4.0878 26.6437 5.97806 29.7235 8.8419 31.7745C9.987 32.5946 11.3079 33.3606 12.5939 33.8365C14.0645 34.3806 15.6064 34.7904 16.6359 34.7904Z" fill="white"/>
</g>
<path id="Devias Material Kit" d="M45.4453 25V10.7812H49.6445C50.901 10.7812 52.0143 11.0612 52.9844 11.6211C53.9609 12.181 54.7161 12.9753 55.25 14.0039C55.7839 15.0326 56.0508 16.2109 56.0508 17.5391V18.252C56.0508 19.5996 55.7806 20.7845 55.2402 21.8066C54.7064 22.8288 53.9414 23.6165 52.9453 24.1699C51.9557 24.7233 50.8197 25 49.5371 25H45.4453ZM47.916 12.7734V23.0273H49.5273C50.8229 23.0273 51.8158 22.6237 52.5059 21.8164C53.2025 21.0026 53.5573 19.8372 53.5703 18.3203V17.5293C53.5703 15.9863 53.235 14.8079 52.5645 13.9941C51.8939 13.1803 50.9206 12.7734 49.6445 12.7734H47.916ZM62.88 25.1953C61.3761 25.1953 60.1554 24.7233 59.2179 23.7793C58.2869 22.8288 57.8214 21.5658 57.8214 19.9902V19.6973C57.8214 18.6426 58.0232 17.7018 58.4269 16.875C58.837 16.0417 59.4099 15.3939 60.1456 14.9316C60.8813 14.4694 61.7016 14.2383 62.6066 14.2383C64.0454 14.2383 65.1554 14.6973 65.9366 15.6152C66.7244 16.5332 67.1183 17.832 67.1183 19.5117V20.4688H60.214C60.2856 21.3411 60.5753 22.0312 61.0831 22.5391C61.5974 23.0469 62.242 23.3008 63.0167 23.3008C64.1039 23.3008 64.9894 22.8613 65.673 21.9824L66.9523 23.2031C66.5291 23.8346 65.9627 24.3262 65.253 24.6777C64.5499 25.0228 63.7589 25.1953 62.88 25.1953ZM62.5968 16.1426C61.9457 16.1426 61.4184 16.3704 61.0148 16.8262C60.6176 17.2819 60.3637 17.9167 60.253 18.7305H64.7745V18.5547C64.7224 17.7604 64.5109 17.1615 64.1398 16.7578C63.7687 16.3477 63.2543 16.1426 62.5968 16.1426ZM72.5022 21.9922L74.7385 14.4336H77.1897L73.5276 25H71.467L67.7756 14.4336H70.2365L72.5022 21.9922ZM81.1478 25H78.7747V14.4336H81.1478V25ZM78.6283 11.6895C78.6283 11.3249 78.7422 11.0221 78.9701 10.7812C79.2044 10.5404 79.5365 10.4199 79.9661 10.4199C80.3958 10.4199 80.7279 10.5404 80.9622 10.7812C81.1966 11.0221 81.3138 11.3249 81.3138 11.6895C81.3138 12.0475 81.1966 12.347 80.9622 12.5879C80.7279 12.8223 80.3958 12.9395 79.9661 12.9395C79.5365 12.9395 79.2044 12.8223 78.9701 12.5879C78.7422 12.347 78.6283 12.0475 78.6283 11.6895ZM89.9985 25C89.8943 24.7982 89.8032 24.4694 89.725 24.0137C88.9698 24.8014 88.0454 25.1953 86.9516 25.1953C85.8904 25.1953 85.0245 24.8926 84.354 24.2871C83.6834 23.6816 83.3481 22.9329 83.3481 22.041C83.3481 20.9147 83.7648 20.0521 84.5981 19.4531C85.4379 18.8477 86.6359 18.5449 88.1918 18.5449H89.6469V17.8516C89.6469 17.3047 89.4939 16.8685 89.1879 16.543C88.8819 16.2109 88.4165 16.0449 87.7915 16.0449C87.2511 16.0449 86.8084 16.1816 86.4633 16.4551C86.1183 16.722 85.9457 17.0638 85.9457 17.4805H83.5727C83.5727 16.901 83.7648 16.3607 84.1489 15.8594C84.533 15.3516 85.0538 14.9544 85.7114 14.668C86.3754 14.3815 87.1144 14.2383 87.9282 14.2383C89.1651 14.2383 90.1515 14.5508 90.8872 15.1758C91.6228 15.7943 92.0004 16.6667 92.02 17.793V22.5586C92.02 23.5091 92.1534 24.2676 92.4204 24.834V25H89.9985ZM87.3911 23.291C87.8598 23.291 88.2993 23.1771 88.7094 22.9492C89.1261 22.7214 89.4386 22.4154 89.6469 22.0312V20.0391H88.3676C87.4887 20.0391 86.8279 20.1921 86.3852 20.498C85.9425 20.804 85.7211 21.237 85.7211 21.7969C85.7211 22.2526 85.8709 22.6172 86.1704 22.8906C86.4763 23.1576 86.8832 23.291 87.3911 23.291ZM100.373 22.1289C100.373 21.7057 100.197 21.3835 99.8453 21.1621C99.5002 20.9408 98.924 20.7454 98.1168 20.5762C97.3095 20.4069 96.6356 20.1921 96.0953 19.9316C94.9104 19.3587 94.3179 18.5286 94.3179 17.4414C94.3179 16.5299 94.702 15.7682 95.4703 15.1562C96.2385 14.5443 97.2151 14.2383 98.4 14.2383C99.663 14.2383 100.682 14.5508 101.457 15.1758C102.238 15.8008 102.628 16.6113 102.628 17.6074H100.255C100.255 17.1517 100.086 16.7741 99.7476 16.4746C99.4091 16.1686 98.9599 16.0156 98.4 16.0156C97.8791 16.0156 97.4527 16.1361 97.1207 16.377C96.7951 16.6178 96.6324 16.9401 96.6324 17.3438C96.6324 17.7083 96.7854 17.9915 97.0914 18.1934C97.3974 18.3952 98.0158 18.6003 98.9468 18.8086C99.8778 19.0104 100.607 19.2546 101.134 19.541C101.668 19.821 102.062 20.1595 102.316 20.5566C102.576 20.9538 102.707 21.4355 102.707 22.002C102.707 22.9525 102.313 23.724 101.525 24.3164C100.737 24.9023 99.7053 25.1953 98.4293 25.1953C97.5634 25.1953 96.7919 25.0391 96.1148 24.7266C95.4377 24.4141 94.9104 23.9844 94.5328 23.4375C94.1552 22.8906 93.9664 22.3014 93.9664 21.6699H96.271C96.3036 22.2298 96.5152 22.6628 96.9058 22.9688C97.2964 23.2682 97.814 23.418 98.4585 23.418C99.0835 23.418 99.5588 23.3008 99.8843 23.0664C100.21 22.8255 100.373 22.513 100.373 22.1289ZM113.963 18.8574L112.351 20.5664V25H109.881V10.7812H112.351V17.4512L113.719 15.7617L117.879 10.7812H120.867L115.584 17.0801L121.17 25H118.24L113.963 18.8574ZM124.737 25H122.364V14.4336H124.737V25ZM122.218 11.6895C122.218 11.3249 122.332 11.0221 122.559 10.7812C122.794 10.5404 123.126 10.4199 123.556 10.4199C123.985 10.4199 124.317 10.5404 124.552 10.7812C124.786 11.0221 124.903 11.3249 124.903 11.6895C124.903 12.0475 124.786 12.347 124.552 12.5879C124.317 12.8223 123.985 12.9395 123.556 12.9395C123.126 12.9395 122.794 12.8223 122.559 12.5879C122.332 12.347 122.218 12.0475 122.218 11.6895ZM130.248 11.8652V14.4336H132.113V16.1914H130.248V22.0898C130.248 22.4935 130.326 22.7865 130.482 22.9688C130.645 23.1445 130.932 23.2324 131.342 23.2324C131.615 23.2324 131.892 23.1999 132.172 23.1348V24.9707C131.632 25.1204 131.111 25.1953 130.609 25.1953C128.786 25.1953 127.875 24.1895 127.875 22.1777V16.1914H126.137V14.4336H127.875V11.8652H130.248Z" fill="white"/>
</g>
</svg>
<svg id="fd59ce54-f850-4dfc-bc34-dd7d379d600e" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="1074.392" height="584.231" viewBox="0 0 1074.392 584.231"><title>page not found</title><ellipse cx="540.64346" cy="549.3094" rx="527.5" ry="34.9216" fill="#f2f2f2"/><path d="M583.47969,324.89424c-85.94407,0-147.651,55.13938-147.651,183.79791,0,145.813,61.70691,184.41057,147.651,184.41057s151.327-42.27352,151.327-184.41057C734.80664,356.75255,669.42376,324.89424,583.47969,324.89424Zm.56495,319.80837c-59.52686,0-90.62592-34.92288-90.62592-135.9163,0-89.11185,32.37209-136.10461,91.899-136.10461s91.899,30.86774,91.899,136.10461C677.21663,607.23367,643.5715,644.70261,584.04464,644.70261Z" transform="translate(-63.054 -157.8845)" fill="#2f2e41"/><path d="M384.36531,591.40121H348.831V486.76183A20.95585,20.95585,0,0,0,327.87517,465.806h-8.32638a20.95585,20.95585,0,0,0-20.95586,20.95585V591.40121H198.36285a11.96327,11.96327,0,0,1-10.57763-17.552l106.0824-200.78034A20.95585,20.95585,0,0,0,284.28724,344.33l-6.26231-2.9572a20.95585,20.95585,0,0,0-27.4293,9.07005L121.21416,592.4754a28.41578,28.41578,0,0,0-3.35584,13.39612v0a28.41583,28.41583,0,0,0,28.41584,28.41583H298.59293v66.16727a25.119,25.119,0,0,0,25.119,25.119h.00005a25.119,25.119,0,0,0,25.119-25.119V634.28739h35.53428a21.44307,21.44307,0,0,0,21.44307-21.44307v0A21.44307,21.44307,0,0,0,384.36531,591.40121Z" transform="translate(-63.054 -157.8845)" fill="#6c63ff"/><path d="M1042.36183,591.40121h-35.53428V486.76183A20.95585,20.95585,0,0,0,985.87169,465.806h-8.32638a20.95585,20.95585,0,0,0-20.95586,20.95585V591.40121H856.35937a11.96326,11.96326,0,0,1-10.57763-17.552L951.86413,373.06891A20.95586,20.95586,0,0,0,942.28376,344.33l-6.26231-2.9572a20.95586,20.95586,0,0,0-27.42931,9.07005L779.21068,592.4754a28.41578,28.41578,0,0,0-3.35584,13.39612v0a28.41583,28.41583,0,0,0,28.41583,28.41583H956.58945v66.16727a25.119,25.119,0,0,0,25.119,25.119h0a25.119,25.119,0,0,0,25.119-25.119V634.28739h35.53428a21.44307,21.44307,0,0,0,21.44307-21.44307v0A21.44307,21.44307,0,0,0,1042.36183,591.40121Z" transform="translate(-63.054 -157.8845)" fill="#6c63ff"/><path d="M394.16787,579.148H358.63358V474.50864a20.95585,20.95585,0,0,0-20.95585-20.95586h-8.32638a20.95586,20.95586,0,0,0-20.95586,20.95586V579.148H208.16541a11.96327,11.96327,0,0,1-10.57763-17.552L303.67017,360.81572a20.95586,20.95586,0,0,0-9.58037-28.73893l-6.26231-2.9572a20.95586,20.95586,0,0,0-27.42931,9.07L131.01672,580.2222a28.41582,28.41582,0,0,0-3.35584,13.39613v0a28.41583,28.41583,0,0,0,28.41583,28.41583H308.39549v66.16727a25.119,25.119,0,0,0,25.119,25.119h.00005a25.119,25.119,0,0,0,25.119-25.119V622.0342h35.53429a21.44307,21.44307,0,0,0,21.44307-21.44307v0A21.44307,21.44307,0,0,0,394.16787,579.148Z" transform="translate(-63.054 -157.8845)" fill="none" stroke="#3f3d56" stroke-miterlimit="10"/><path d="M1060.74162,579.148h-35.53428V474.50864a20.95586,20.95586,0,0,0-20.95586-20.95586H995.9251a20.95586,20.95586,0,0,0-20.95586,20.95586V579.148H874.73916a11.96327,11.96327,0,0,1-10.57763-17.552L970.24392,360.81572a20.95586,20.95586,0,0,0-9.58037-28.73893l-6.26231-2.9572a20.95586,20.95586,0,0,0-27.42931,9.07L797.59047,580.2222a28.41582,28.41582,0,0,0-3.35584,13.39613v0a28.41583,28.41583,0,0,0,28.41583,28.41583H974.96924v66.16727a25.119,25.119,0,0,0,25.119,25.119h0a25.119,25.119,0,0,0,25.119-25.119V622.0342h35.53428a21.44307,21.44307,0,0,0,21.44307-21.44307v0A21.44307,21.44307,0,0,0,1060.74162,579.148Z" transform="translate(-63.054 -157.8845)" fill="none" stroke="#3f3d56" stroke-miterlimit="10"/><path d="M603.0848,313.86637c-85.94407,0-147.651,55.13937-147.651,183.79791,0,145.813,61.70691,184.41057,147.651,184.41057s151.327-42.27352,151.327-184.41057C754.41175,345.72467,689.02887,313.86637,603.0848,313.86637Zm.565,319.80836c-59.52686,0-90.62592-34.92287-90.62592-135.91629,0-89.11185,32.37209-136.10461,91.899-136.10461s91.899,30.86774,91.899,136.10461C696.82174,596.20579,663.17661,633.67473,603.64975,633.67473Z" transform="translate(-63.054 -157.8845)" fill="none" stroke="#3f3d56" stroke-miterlimit="10"/><circle cx="471.14108" cy="18.25044" r="12.90118" fill="#2f2e41"/><ellipse cx="502.60736" cy="46.88476" rx="36.18622" ry="46.88476" fill="#2f2e41"/><path d="M565.66136,237.49419c-18.1276,0-33.1413-17.27052-35.77576-39.80484a60.9759,60.9759,0,0,0-.41046,7.07991c0,25.89373,16.20114,46.88476,36.18622,46.88476s36.18623-20.991,36.18623-46.88476a60.9759,60.9759,0,0,0-.41046-7.07991C598.80267,220.22367,583.789,237.49419,565.66136,237.49419Z" transform="translate(-63.054 -157.8845)" opacity="0.1"/><path d="M639.29619,342.07326c-.77711,3.19345-4.12792,5.751-7.83881,7.53791-7.80188,3.75682-17.4253,4.87788-26.7597,5.25418a45.17622,45.17622,0,0,1-7.1445-.132,20.5371,20.5371,0,0,1-12.25052-5.63141,1.68086,1.68086,0,0,1,.04371-2.84388c4.9694-5.45888,13.2622-8.80605,21.61613-11.21609,6.3344-1.82743,17.3813-6.56089,24.29013-5.9221C637.94444,329.73864,640.2774,338.04112,639.29619,342.07326Z" transform="translate(-63.054 -157.8845)" fill="#3f3d56"/><path d="M639.29619,342.07326c-.77711,3.19345-4.12792,5.751-7.83881,7.53791-7.80188,3.75682-17.4253,4.87788-26.7597,5.25418a45.17622,45.17622,0,0,1-7.1445-.132,20.5371,20.5371,0,0,1-12.25052-5.63141,1.68086,1.68086,0,0,1,.04371-2.84388c4.9694-5.45888,13.2622-8.80605,21.61613-11.21609,6.3344-1.82743,17.3813-6.56089,24.29013-5.9221C637.94444,329.73864,640.2774,338.04112,639.29619,342.07326Z" transform="translate(-63.054 -157.8845)" opacity="0.1"/><path d="M540.09786,318.2059a19.76967,19.76967,0,0,0-1.1987,15.07476,26.33914,26.33914,0,0,0,8.82921,12.49683c10.09467,8.09163,23.98784,9.20512,36.92477,9.09278a284.6495,284.6495,0,0,0,33.90525-2.32384,40.53788,40.53788,0,0,0,11.00143-2.55442c4.22242-1.82679,7.93282-5.17756,9.436-9.5257s.43625-9.67246-3.13383-12.57428c-3.13686-2.54969-7.46265-2.9004-11.49775-3.14289l-23.08764-1.38745c2.281-2.30839,5.31816-3.614,8.09586-5.29216,3.68523-2.22642,6.13358-5.96455,8.81312-9.33471a129.00143,129.00143,0,0,1,13.4386-13.817c.75138,4.31038,3.4782,7.8499,6.68733,10.824s6.90841,5.36845,10.2439,8.20013c8.0786,6.85838,13.89583,16.1669,22.39215,22.50043a43.82885,43.82885,0,0,0,16.04862-8.0122l-3.30209-5.98141a3.94,3.94,0,0,0-1.24459-1.55282c-.93465-.575-2.13975-.27872-3.225-.44144-2.90082-.435-4.16771-3.784-5.306-6.48737-3.12491-7.42173-9.108-13.17993-14.21783-19.40381a98.00854,98.00854,0,0,1-9.99577-14.72284c-1.71652-3.10162-3.288-6.33107-5.61746-9.00321s-5.59358-4.773-9.1385-4.78051c-3.13222-.00662-6.02122,1.58355-8.71422,3.18308a230.47679,230.47679,0,0,0-23.63018,16.09894c-3.94376,3.0617-7.86306,6.29645-12.48933,8.17393-1.94748.79035-4.00044,1.33052-5.86924,2.29223-3.27313,1.6844-5.75721,4.53435-8.43128,7.06415C566.27712,311.89225,553.219,317.73841,540.09786,318.2059Z" transform="translate(-63.054 -157.8845)" fill="#3f3d56"/><path d="M588.3737,253.98251a23.77444,23.77444,0,0,1-1.73379,8.03335,10.04492,10.04492,0,0,1-5.76772,5.57269,12.37513,12.37513,0,0,1-5.62306.18249,10.88232,10.88232,0,0,1-4.58151-1.56071c-2.16484-1.48837-3.24415-4.14413-3.63748-6.74325-.39333-2.596-.21714-5.24857-.46885-7.86342a42.94439,42.94439,0,0,0-1.202-6.25549c-.16993-.68282-.343-1.36248-.51294-2.04216-.16674-.67967-.33037-1.35935-.48141-2.039-.13847-.63878-.26745-1.28068-.37761-1.92574-.09123-.54436-.173-1.09189-.23285-1.64255a18.42329,18.42329,0,0,0-.80867-4.81118,14.60727,14.60727,0,0,0-1.68659-2.854c-.28635-.40906-.56326-.81811-.81815-1.24292a5.88984,5.88984,0,0,1-.97226-3.74763,3.286,3.286,0,0,1,.14788-.601c.02516-.07552.05347-.151.085-.2234A1.80187,1.80187,0,0,0,560.932,223.07a3.43341,3.43341,0,0,0-.14788-1.77783,11.31808,11.31808,0,0,0-.95974-2.28761c-.2643-.47829-1.16108-1.34046-1.16738-1.888-.0126-1.10132,2.13972-1.98867,3.01134-2.42291a16.79623,16.79623,0,0,1,8.59657-1.74323c1.90369.129,3.9679.71428,5.0189,2.30962.944,1.438.81807,3.30081,1.22085,4.97169a1.47068,1.47068,0,0,0,.29892.66393,1.34135,1.34135,0,0,0,.73948.33982,4.54948,4.54948,0,0,0,1.416.05666h.00315a2.93138,2.93138,0,0,0,.37128-.05351,4.957,4.957,0,0,0,2.03271-.8779q.58531-.15576,1.18-.25488a.25112.25112,0,0,0,.04725-.00945c1.57646,4.97482,1.781,10.30836,3.07111,15.37444.63874,2.52044,1.55442,5.00943,1.6834,7.60225.00945.11327.0126.2297.01575.34612.0189.83386-.04717,1.674-.0126,2.50472a6.981,6.981,0,0,0,.12591,1.1139,15.61121,15.61121,0,0,0,.52546,1.74325l.00945.02831c.05977.18251.11643.36817.16363.55381.03457.1353.06607.26747.09127.40277l.00311.00943A14.93754,14.93754,0,0,1,588.3737,253.98251Z" transform="translate(-63.054 -157.8845)" fill="#fbbebe"/><circle cx="503.23669" cy="44.99678" r="18.56511" fill="#fbbebe"/><path d="M684.15711,304.03278a30.445,30.445,0,0,0-5.236-14.10317q.72216,4.29513,1.44748,8.58714a3.214,3.214,0,0,1-3.36688-1.03523,10.33663,10.33663,0,0,1-1.76529-3.27565,67.46571,67.46571,0,0,0-8.2095-14.73567c-11.81876-.98489-23.50223-5.88418-33.89555-11.59532-10.39643-5.708-20.12582-12.5519-30.38382-18.50217a43.57346,43.57346,0,0,0-5.54436-2.832c-3.20954-1.287-6.81242-1.95406-9.85526-3.46759-.2045-.1007-.409-.20767-.61043-.31781a12.57834,12.57834,0,0,1-1.94459-1.30584,10.34363,10.34363,0,0,1-.93139-.8559,20.35115,20.35115,0,0,1-3.55886-5.95341c-1.63308-3.61232-2.21524-7.97041-3.84517-11.58274a11.20292,11.20292,0,0,1,2.50156-1.76525h.00315c.13213-.06924.2643-.13532.39962-.19824a11.9404,11.9404,0,0,1,2.00437-.73317q.58531-.15576,1.18-.25488a.25112.25112,0,0,0,.04725-.00945,11.56564,11.56564,0,0,1,5.49085.43424c2.58652.87477,4.76711,2.62115,6.94148,4.27313a114.02006,114.02006,0,0,1,10.14787,8.04908c1.79357,1.718,3.4298,3.606,5.35868,5.16676a42.14393,42.14393,0,0,0,5.05662,3.35116q15.65613,9.32658,31.31525,18.65005c3.53365,2.1051,7.07046,4.21019,10.52553,6.438,5.24855,3.38578,10.30828,7.05474,15.36493,10.72057q4.46978,3.23787,8.93647,6.47889a9.72771,9.72771,0,0,1,2.533,2.3411,8.4724,8.4724,0,0,1,1.12337,3.433A31.3874,31.3874,0,0,1,684.15711,304.03278Z" transform="translate(-63.054 -157.8845)" fill="#fbbebe"/><path d="M592.97726,267.9441c-1.25235,5.61674-6.92888,9.012-9.89617,13.94586-3.68784,6.12335-2.18378,13.241-.79922,20.25484q-3.79485,3.27095-7.59285,6.54186c-1.39708,1.19886-2.79417,2.404-4.29827,3.46444a57.35064,57.35064,0,0,1-6.85966,3.93956q-3.3606,1.72752-6.72119,3.45814a32.1282,32.1282,0,0,1-6.57961,2.78793c-4.41473,1.13278-9.10318.33982-13.4707-.97232a6.08761,6.08761,0,0,1-1.47264-.601,2.39351,2.39351,0,0,1-.69854-.63248,3.91067,3.91067,0,0,1-.44365-2.53933c.44365-7.35052,2.24036-14.54686,4.03081-21.68971a85.2598,85.2598,0,0,1,3.84832-12.57708,85.0766,85.0766,0,0,1,5.41538-10.151,68.36751,68.36751,0,0,1,7.92948-11.51353,18.47881,18.47881,0,0,0,3.67525-4.73882c1.11706-2.54876.686-5.472.91252-8.24732a17.14844,17.14844,0,0,1,1.63312-6.0069v-.00315a17.09326,17.09326,0,0,1,1.74321-2.88232q.45788,1.06671.91568,2.13027.30209.69855.59783,1.394.38706.89679.7678,1.78728,1.09973,2.55823,2.19637,5.11327a21.58968,21.58968,0,0,0,3.33538,5.944,6.49923,6.49923,0,0,0,11.12337-.85275,21.26125,21.26125,0,0,0,2.27185-6.0132,19.21547,19.21547,0,0,0,.25175-7.83509c-.75835-5.00945-2.88862-10.12585-4.43678-14.77972a14.94511,14.94511,0,0,1-1.07927-4.871,3.35144,3.35144,0,0,1,.05662-.56011c.00945-.04719.0189-.09754.02834-.14473a11.9404,11.9404,0,0,1,2.00437-.73317q.58531-.15576,1.18-.25488,2.04378,11.06355,4.09377,22.12709c.0315.17307.0661.34613.09756.52234.19509,1.05726.39333,2.11454.61358,3.16865.19828.95657.41223,1.91.65137,2.85715l.00945.02831c.08182.321.16678.63877.2549.95658l.00311.00943c.2423.86848.5129,1.73065.81811,2.58024C590.93825,257.47528,594.16355,262.62946,592.97726,267.9441Z" transform="translate(-63.054 -157.8845)" fill="#6c63ff"/><path d="M668.32144,346.87707a6.58269,6.58269,0,0,0,.61,3.14328c1.16192,2.12353,3.94981,2.60625,6.36228,2.80484a188.37688,188.37688,0,0,0,42.2657-1.28774,4.88565,4.88565,0,0,0,2.15136-.66766c1.98985-1.39509.76329-4.7951-1.40951-5.88355s-4.75126-.82614-7.1353-1.29748a22.47912,22.47912,0,0,1-6.67794-2.89617q-7.25234-4.16669-14.293-8.68808c-2.79453-1.79464-6.09272-3.70993-9.23987-2.64587C672.43,332.34264,668.26533,337.68065,668.32144,346.87707Z" transform="translate(-63.054 -157.8845)" fill="#3f3d56"/><path d="M564.43732,240.87367v.00315c-.022.13215-.04406.26116-.07237.39018-.0346.214-.07551.43108-.11642.645-.39018,1.99812-.86847,3.98678-1.41913,5.96287-1.5104,5.45939-3.53366,10.83069-5.54121,16.12332q-8.08055,21.28692-16.16423,42.577c-1.35936,3.57457-2.71554,7.15228-4.26054,10.65448-.516,1.16741-1.04782,2.34424-1.57647,3.53368-1.89427,4.25737-3.713,8.65322-4.31716,13.18436a27.44976,27.44976,0,0,0-.19194,9.04027c.60416,2.97042,2.40718,5.8716,5.22969,6.96977,1.37823.53808,3.35113,1.25865,2.97355,2.69037-.2045.78665-1.09817,1.17055-1.90057,1.3027a7.31234,7.31234,0,0,1-5.966-1.718c-1.50725-1.33732-2.66518-3.41725-4.66959-3.64065-1.38767-.151-2.66518.67966-3.93643,1.26178-5.18564,2.36942-11.22719.71114-16.674-.9723.42794-2.20579,2.64318-3.65953,4.84267-4.10006,2.19949-.44367,4.47449-.129,6.718-.18879a3.50958,3.50958,0,0,0,2.04216-.52549,3.70545,3.70545,0,0,0,1.10132-1.88169,78.96356,78.96356,0,0,0,3.21273-13.14661c.7237-4.66645,1.02581-9.40527,2.05787-14.01507.80241-3.59661,2.0422-7.07991,3.10572-10.61044a224.68238,224.68238,0,0,0,5.0598-22.07674,78.02019,78.02019,0,0,0,1.42543-9.36751c.17935-2.6117.09438-5.236.34609-7.83826a60.8877,60.8877,0,0,1,2.11141-9.99683q1.44427-5.34769,2.88547-10.68911c1.42544-5.2706,2.95465-10.74572,6.567-14.84264a13.96159,13.96159,0,0,1,10.02834-4.78915,9.8819,9.8819,0,0,1,2.13027.22969c.11639.02831.23285.05664.34923.0881a8.63447,8.63447,0,0,1,2.17437.89995c1.11388-.708,1.68025-.45942,2.41974.63246a6.97319,6.97319,0,0,1,.88107,3.79485A52.42378,52.42378,0,0,1,564.43732,240.87367Z" transform="translate(-63.054 -157.8845)" fill="#fbbebe"/><path d="M565.66136,245.0461l-.0472.04719-.25486.25488-2.5299,2.52675-1.23976-5.20767-4.25109-17.854a9.8819,9.8819,0,0,1,2.13027.22969,3.286,3.286,0,0,1,.14788-.601l.20135.68911,1.44118,4.90245,2.72811,9.30773.45,1.53241v.00315Z" transform="translate(-63.054 -157.8845)" fill="#6c63ff"/><path d="M581.71523,188.0873a12.58165,12.58165,0,0,1-3.70049,8.89583,12.31392,12.31392,0,0,1-1.36008,1.17634,12.52812,12.52812,0,0,1-7.53567,2.52415H554.023a12.5902,12.5902,0,0,1,0-25.18037h15.096A12.62919,12.62919,0,0,1,581.71523,188.0873Z" transform="translate(-63.054 -157.8845)" fill="#2f2e41"/><circle cx="532.81499" cy="18.25044" r="12.90118" fill="#2f2e41"/><path d="M595.55433,163.23377c-.15825,0-.31505.00628-.472.01193a12.89776,12.89776,0,0,1,0,25.77849c.15694.00565.31374.01193.472.01193a12.90117,12.90117,0,1,0,0-25.80235Z" transform="translate(-63.054 -157.8845)" opacity="0.1"/><path d="M534.19508,163.23377c.15825,0,.31505.00628.472.01193a12.89776,12.89776,0,0,0,0,25.77849c-.157.00565-.31375.01193-.472.01193a12.90118,12.90118,0,0,1,0-25.80235Z" transform="translate(-63.054 -157.8845)" opacity="0.1"/><path d="M576.65466,198.15947a12.52812,12.52812,0,0,1-7.53567,2.52415H554.023a12.52833,12.52833,0,0,1-7.53574-2.52415Z" transform="translate(-63.054 -157.8845)" opacity="0.1"/><path d="M674.13958,291.64042s3.25228,9.37161,6.229,6.87633L677.996,286.26693Z" transform="translate(-63.054 -157.8845)" fill="#fbbebe"/><path d="M1069.91781,577.43414a20.81252,20.81252,0,1,0,2.7716-39.91524l.52093,10.7122-5.06814-9.18045a20.734,20.734,0,0,0-10.68367,11.72261,20.40847,20.40847,0,0,0-1.19713,5.62986A20.80856,20.80856,0,0,0,1069.91781,577.43414Z" transform="translate(-63.054 -157.8845)" fill="#57b894"/><path d="M1094.99516,701.67756c-1.78906-9.11027,5.9633-17.1868,13.62086-22.43651s16.605-10.40779,19.21775-19.31684c3.755-12.80387-7.43-24.52981-16.13564-34.64176a125.30044,125.30044,0,0,1-16.52359-24.55738c-1.81107-3.5325-3.47558-7.22528-3.95221-11.16626-.68641-5.67546,1.13693-11.32309,2.9739-16.73673q9.17925-27.05169,19.62843-53.65005" transform="translate(-63.054 -157.8845)" fill="none" stroke="#3f3d56" stroke-miterlimit="10"/><path d="M1070.77493,574.6762a20.81252,20.81252,0,1,0,2.7716-39.91524l.52093,10.7122-5.06815-9.18045a20.734,20.734,0,0,0-10.68366,11.72261,20.40847,20.40847,0,0,0-1.19713,5.62986A20.80855,20.80855,0,0,0,1070.77493,574.6762Z" transform="translate(-63.054 -157.8845)" fill="none" stroke="#3f3d56" stroke-miterlimit="10"/><path d="M1092.45136,515.47266a20.78819,20.78819,0,0,1,14.97993-13.19764l1.71361,10.18378,3.177-10.69566a20.81,20.81,0,1,1-19.87057,13.70952Z" transform="translate(-63.054 -157.8845)" fill="#57b894"/><path d="M1093.59418,511.7954a20.7882,20.7882,0,0,1,14.97993-13.19763l1.71361,10.18378,3.177-10.69567a20.81,20.81,0,1,1-19.87057,13.70952Z" transform="translate(-63.054 -157.8845)" fill="none" stroke="#3f3d56" stroke-miterlimit="10"/><path d="M1108.04474,625.48885a20.81,20.81,0,0,0,18.419-37.02267l-2.44121,8.21926-1.73105-10.30382a.36183.36183,0,0,0-.053-.0201,20.81113,20.81113,0,1,0-14.1938,39.12733Z" transform="translate(-63.054 -157.8845)" fill="#57b894"/><path d="M1109.035,621.76417a20.81,20.81,0,0,0,18.419-37.02267l-2.44121,8.21926-1.73105-10.30382a.3621.3621,0,0,0-.053-.0201,20.81113,20.81113,0,1,0-14.1938,39.12733Z" transform="translate(-63.054 -157.8845)" fill="none" stroke="#3f3d56" stroke-miterlimit="10"/><path d="M1086.37782,660.05148a20.80131,20.80131,0,1,0,4.01058-16.29737l9.27267,13.95654-12.66994-7.40768A20.61638,20.61638,0,0,0,1086.37782,660.05148Z" transform="translate(-63.054 -157.8845)" fill="#57b894"/><path d="M1087.23494,657.29354a20.80131,20.80131,0,1,0,4.01058-16.29737l9.27267,13.95655-12.66994-7.40769A20.61626,20.61626,0,0,0,1087.23494,657.29354Z" transform="translate(-63.054 -157.8845)" fill="none" stroke="#3f3d56" stroke-miterlimit="10"/><path d="M72.06146,628.13325a13.67421,13.67421,0,1,0,1.821-26.225l.34227,7.03811-3.32987-6.03172a13.62263,13.62263,0,0,0-7.01936,7.702,13.40883,13.40883,0,0,0-.78654,3.69893A13.6716,13.6716,0,0,0,72.06146,628.13325Z" transform="translate(-63.054 -157.8845)" fill="#57b894"/><path d="M88.53774,709.76344c-1.17545-5.98561,3.918-11.292,8.94915-14.7412s10.90978-6.8381,12.62642-12.69151c2.46711-8.41238-4.88167-16.11653-10.60142-22.76027A82.32442,82.32442,0,0,1,88.6556,643.43581a22.20962,22.20962,0,0,1-2.59668-7.33643c-.451-3.72888.747-7.43947,1.95391-10.99634q6.03093-17.77346,12.89623-35.24906" transform="translate(-63.054 -157.8845)" fill="none" stroke="#3f3d56" stroke-miterlimit="10"/><path d="M72.62461,626.32123a13.6742,13.6742,0,1,0,1.821-26.225l.34227,7.03812L71.458,601.10258a13.62262,13.62262,0,0,0-7.01936,7.702,13.40912,13.40912,0,0,0-.78654,3.69892A13.67158,13.67158,0,0,0,72.62461,626.32123Z" transform="translate(-63.054 -157.8845)" fill="none" stroke="#3f3d56" stroke-miterlimit="10"/><path d="M86.86641,587.42343a13.65822,13.65822,0,0,1,9.84209-8.67109l1.12587,6.69093,2.08737-7.02725a13.67252,13.67252,0,1,1-13.05533,9.00741Z" transform="translate(-63.054 -157.8845)" fill="#57b894"/><path d="M87.61727,585.0074a13.65822,13.65822,0,0,1,9.84209-8.67108l1.12587,6.69093L100.6726,576a13.67252,13.67252,0,1,1-13.05533,9.0074Z" transform="translate(-63.054 -157.8845)" fill="none" stroke="#3f3d56" stroke-miterlimit="10"/><path d="M97.11155,659.70607a13.67255,13.67255,0,0,0,12.10164-24.32457l-1.60392,5.4002-1.13733-6.76979a.238.238,0,0,0-.0348-.0132,13.67329,13.67329,0,1,0-9.32559,25.70736Z" transform="translate(-63.054 -157.8845)" fill="#57b894"/><path d="M97.76214,657.25889a13.67255,13.67255,0,0,0,12.10164-24.32457l-1.60392,5.4002-1.13733-6.7698a.238.238,0,0,0-.0348-.0132,13.67329,13.67329,0,1,0-9.32559,25.70737Z" transform="translate(-63.054 -157.8845)" fill="none" stroke="#3f3d56" stroke-miterlimit="10"/><path d="M82.876,682.41435a13.66684,13.66684,0,1,0,2.635-10.70767l6.09231,9.16971-8.32438-4.867A13.54535,13.54535,0,0,0,82.876,682.41435Z" transform="translate(-63.054 -157.8845)" fill="#57b894"/><path d="M83.43913,680.60233a13.66684,13.66684,0,1,0,2.635-10.70767l6.09231,9.16971-8.32439-4.867A13.54535,13.54535,0,0,0,83.43913,680.60233Z" transform="translate(-63.054 -157.8845)" fill="none" stroke="#3f3d56" stroke-miterlimit="10"/><ellipse cx="480.946" cy="319.1155" rx="17" ry="22" fill="#2f2e41"/><ellipse cx="573.446" cy="319.6155" rx="17" ry="22" fill="#2f2e41"/><path d="M623.5,542.5c0,9.94-13.88,18-31,18s-31-8.06-31-18c0-8.61,10.41-15.81,24.32-17.57a50.10353,50.10353,0,0,1,6.68-.43,50.69869,50.69869,0,0,1,11.13,1.2C615.25,528.29,623.5,534.84,623.5,542.5Z" transform="translate(-63.054 -157.8845)" fill="#2f2e41"/><ellipse cx="484.946" cy="314.1155" rx="17" ry="22" fill="none" stroke="#3f3d56" stroke-miterlimit="10"/><ellipse cx="577.446" cy="314.6155" rx="17" ry="22" fill="none" stroke="#3f3d56" stroke-miterlimit="10"/><ellipse cx="533.446" cy="379.6155" rx="31" ry="18" fill="none" stroke="#3f3d56" stroke-miterlimit="10"/><path d="M604,527.2a4.93658,4.93658,0,0,1-1.32,3.392A4.33873,4.33873,0,0,1,599.5,532h-10a4.66433,4.66433,0,0,1-4.5-4.8,4.90458,4.90458,0,0,1,.82-2.74134A47.02,47.02,0,0,1,592.5,524a47.66454,47.66454,0,0,1,11.13,1.28A5.06656,5.06656,0,0,1,604,527.2Z" transform="translate(-63.054 -157.8845)" fill="#fff"/><circle cx="484.946" cy="308.1155" r="5" fill="#fff"/><circle cx="577.946" cy="308.1155" r="5" fill="#fff"/><circle cx="582.946" cy="355.1155" r="5" fill="#6c63ff" opacity="0.3"/><circle cx="460.946" cy="355.1155" r="5" fill="#6c63ff" opacity="0.3"/></svg>
\ No newline at end of file
<svg id="0b188637-16b1-4c40-a71f-ceebe5cfc5ec" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="729.22" height="746.14" viewBox="0 0 729.22 746.14"><defs><linearGradient id="161b0b7e-f39b-42f9-9ca9-e5f4182b27e7" x1="459.12" y1="621" x2="459.12" y2="193.38" gradientTransform="translate(-9.77 -29.03)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="gray" stop-opacity="0.25"/><stop offset="0.54" stop-color="gray" stop-opacity="0.12"/><stop offset="1" stop-color="gray" stop-opacity="0.1"/></linearGradient><linearGradient id="0379165a-8b01-4db8-a9fd-a7f74912e5f9" x1="459.12" y1="355.96" x2="459.12" y2="192.97" gradientTransform="translate(-44.96 -24.28)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#b3b3b3" stop-opacity="0.25"/><stop offset="0.54" stop-color="#b3b3b3" stop-opacity="0.1"/><stop offset="1" stop-color="#b3b3b3" stop-opacity="0.05"/></linearGradient><linearGradient id="a5c94603-d688-4cb8-935e-8753937e09f1" x1="890.03" y1="384.1" x2="893.49" y2="466.67" gradientTransform="matrix(-0.96, 0.28, -0.28, -0.96, 1290.21, 438.32)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-opacity="0.12"/><stop offset="0.55" stop-opacity="0.09"/><stop offset="1" stop-opacity="0.02"/></linearGradient><linearGradient id="452544f9-f0e1-48f7-bf2a-2e6d32ceef9c" x1="630.78" y1="714.25" x2="630.78" y2="285.78" gradientTransform="matrix(1, 0, 0, 1, 0, 0)" xlink:href="#161b0b7e-f39b-42f9-9ca9-e5f4182b27e7"/><linearGradient id="b357cf12-7038-49e2-a945-bede915bae9c" x1="737.4" y1="672.7" x2="737.4" y2="245.08" gradientTransform="translate(15.96 0.36)" xlink:href="#161b0b7e-f39b-42f9-9ca9-e5f4182b27e7"/><linearGradient id="ea27b32b-d891-4df9-a7ed-488b1d56dfe9" x1="737.4" y1="407.66" x2="737.4" y2="244.68" gradientTransform="translate(1.98 1.1)" xlink:href="#0379165a-8b01-4db8-a9fd-a7f74912e5f9"/><linearGradient id="e9a0bbc5-d046-4610-9b74-eda9798afd67" x1="612.39" y1="329.04" x2="615.85" y2="411.61" gradientTransform="translate(1291.19 632.77) rotate(173.26)" xlink:href="#a5c94603-d688-4cb8-935e-8753937e09f1"/><linearGradient id="d89d3977-de30-46d1-ab57-98fa636459b9" x1="382.92" y1="428.03" x2="382.92" y2="0.4" gradientTransform="matrix(1, 0, 0, 1, 0, 0)" xlink:href="#161b0b7e-f39b-42f9-9ca9-e5f4182b27e7"/><linearGradient id="1e925d76-3047-4c1e-82a0-04113f14e226" x1="382.92" y1="162.99" x2="382.92" y2="0" gradientTransform="matrix(1, 0, 0, 1, 0, 0)" xlink:href="#0379165a-8b01-4db8-a9fd-a7f74912e5f9"/><linearGradient id="9a56d00c-164c-4fec-8f17-f5f893f4fff9" x1="729.45" y1="498.21" x2="732.9" y2="580.79" gradientTransform="matrix(-1, 0.01, -0.01, -1, 1253.94, 688.13)" xlink:href="#a5c94603-d688-4cb8-935e-8753937e09f1"/><linearGradient id="595bce0a-5d70-43e8-a094-99f33f4517de" x1="328.81" y1="746.14" x2="328.81" y2="254.91" gradientTransform="matrix(1, 0, 0, 1, 0, 0)" xlink:href="#161b0b7e-f39b-42f9-9ca9-e5f4182b27e7"/><linearGradient id="7d63bf16-77e8-4c09-b275-41a64fa57a97" x1="329.34" y1="675.01" x2="329.34" y2="373.01" gradientTransform="matrix(1, 0, 0, 1, 0, 0)" xlink:href="#161b0b7e-f39b-42f9-9ca9-e5f4182b27e7"/><linearGradient id="cafffc46-2bab-4c9b-8a17-f57a9c7cb665" x1="683.6" y1="52.97" x2="690.12" y2="208.87" gradientTransform="matrix(-1, 0.01, -0.01, -1, 1253.94, 688.13)" xlink:href="#a5c94603-d688-4cb8-935e-8753937e09f1"/></defs><title>resume folder_2</title><rect x="286.73" y="164.35" width="325.25" height="427.62" transform="matrix(0.96, -0.27, 0.27, 0.96, -319.57, 55.74)" fill="url(#161b0b7e-f39b-42f9-9ca9-e5f4182b27e7)"/><rect x="251.16" y="168.7" width="326" height="162.99" transform="translate(-286.9 41.83) rotate(-15.37)" fill="url(#0379165a-8b01-4db8-a9fd-a7f74912e5f9)"/><rect x="290.45" y="167.72" width="316.93" height="417.67" transform="translate(-319.16 55.57) rotate(-15.37)" fill="#eee"/><rect x="255.71" y="171.97" width="317.66" height="159.19" transform="translate(-287.25 41.98) rotate(-15.37)" fill="#3f51b5"/><rect x="358.16" y="384.47" width="86.17" height="6.57" transform="translate(-323.84 43.33) rotate(-15.37)" fill="#bdbdbd"/><rect x="365.13" y="409.82" width="86.17" height="6.57" transform="translate(-330.31 46.09) rotate(-15.37)" fill="#f5f5f5"/><rect x="359.16" y="378.75" width="224.92" height="6.57" transform="translate(-319.8 61.79) rotate(-15.37)" fill="#69f0ae"/><rect x="375.45" y="229.76" width="86.17" height="6.57" transform="translate(-282.2 42.38) rotate(-15.37)" fill="#fff"/><rect x="378.38" y="236.87" width="138.75" height="6.57" transform="translate(-283.04 50.38) rotate(-15.37)" fill="#fff"/><rect x="409.8" y="255.17" width="86.17" height="7.3" rx="3.09" ry="3.09" transform="translate(-287.8 52.41) rotate(-15.37)" opacity="0.2"/><circle cx="325.31" cy="413.18" r="15.34" transform="translate(-333.29 24.11) rotate(-15.37)" fill="#69f0ae"/><rect x="375.01" y="445.73" width="86.17" height="6.57" transform="translate(-339.47 49.99) rotate(-15.37)" fill="#bdbdbd"/><rect x="381.98" y="471.08" width="86.17" height="6.57" transform="translate(-345.95 52.75) rotate(-15.37)" fill="#f5f5f5"/><rect x="376.01" y="440.01" width="224.92" height="6.57" transform="translate(-335.44 68.45) rotate(-15.37)" fill="#e0e0e0"/><circle cx="342.15" cy="474.44" r="15.34" transform="translate(-348.93 30.77) rotate(-15.37)" fill="#e0e0e0"/><rect x="391.85" y="506.98" width="86.17" height="6.57" transform="translate(-355.11 56.65) rotate(-15.37)" fill="#bdbdbd"/><rect x="398.82" y="532.33" width="86.17" height="6.57" transform="translate(-361.58 59.4) rotate(-15.37)" fill="#f5f5f5"/><rect x="392.85" y="501.27" width="224.92" height="6.57" transform="translate(-351.08 75.1) rotate(-15.37)" fill="#e0e0e0"/><circle cx="359" cy="535.7" r="15.34" transform="translate(-364.57 37.43) rotate(-15.37)" fill="#e0e0e0"/><path d="M274.62,287.15A42.28,42.28,0,1,0,318,233.24l3,10.47a14.36,14.36,0,0,1-9.8,17.72h0a14.36,14.36,0,0,1-17.72-9.8l-3-10.47A42.3,42.3,0,0,0,274.62,287.15Z" transform="translate(-235.39 -76.93)" fill="url(#a5c94603-d688-4cb8-935e-8753937e09f1)"/><path d="M355,260.43a42.28,42.28,0,1,0-44,53.38l-2.89-10.5a14.36,14.36,0,0,1,10-17.6h0a14.36,14.36,0,0,1,17.6,10l2.89,10.5A42.3,42.3,0,0,0,355,260.43Z" transform="translate(-235.39 -76.93)" fill="#3f51b5"/><circle cx="312.7" cy="266.03" r="16.25" transform="translate(-294.73 15.5) rotate(-15.37)" fill="#fff" stroke="#fff" stroke-miterlimit="10"/><path d="M318.09,285.71h0a14.36,14.36,0,0,0-10,17.6l2.89,10.5a42.44,42.44,0,0,0,27.61-7.59l-2.89-10.5A14.36,14.36,0,0,0,318.09,285.71Z" transform="translate(-235.39 -76.93)" fill="#fff" stroke="#fff" stroke-miterlimit="10"/><path d="M296.66,269.51a15.77,15.77,0,0,1-3.84-7.42,10.93,10.93,0,0,1,1.51-8.11c1.75-2.57,4.65-4.11,7.58-5.17s6-1.75,8.78-3.14a19.44,19.44,0,0,0,9.74-11.41,26.14,26.14,0,0,1,1.83,6.92,8.81,8.81,0,0,1-2,6.68c2.08-1.76,2.53.9,2.44,2.59,1.57,1.1,4.5.55,5.16,2.35a12,12,0,0,1,.9,5.61c-.25,1.9,1.34,4.68-.46,5.32" transform="translate(-235.39 -76.93)" fill="#fff" stroke="#fff" stroke-miterlimit="10"/><path d="M321,247.24s11.2-2.05,7.87,16.32" transform="translate(-235.39 -76.93)" fill="#fff"/><polygon points="637.77 714.25 532.34 714.25 532.34 285.78 729.22 285.78 637.77 714.25" fill="url(#452544f9-f0e1-48f7-bf2a-2e6d32ceef9c)"/><polygon points="632.52 714.25 529.17 714.25 529.17 285.78 722.16 285.78 632.52 714.25" fill="#bdbdbd"/><rect x="590.74" y="245.44" width="325.25" height="427.62" transform="translate(-279.59 5.03) rotate(-6.05)" fill="url(#b357cf12-7038-49e2-a945-bede915bae9c)"/><rect x="576.38" y="245.78" width="326" height="162.99" transform="translate(-265.76 2.82) rotate(-6.05)" fill="url(#ea27b32b-d891-4df9-a7ed-488b1d56dfe9)"/><rect x="594.73" y="248.76" width="316.93" height="417.67" transform="translate(-279.42 5) rotate(-6.05)" fill="#f5f5f5"/><rect x="580.7" y="249.09" width="317.66" height="159.19" transform="translate(-265.91 2.84) rotate(-6.05)" fill="#3f51b5"/><rect x="661.26" y="457.64" width="86.17" height="6.57" transform="translate(-280.04 -0.13) rotate(-6.05)" fill="#bdbdbd"/><rect x="664.03" y="483.78" width="86.17" height="6.57" transform="translate(-282.78 0.31) rotate(-6.05)" fill="#f5f5f5"/><rect x="662.26" y="463.4" width="224.92" height="6.57" transform="translate(-280.26 7.32) rotate(-6.05)" fill="#69f0ae"/><rect x="703.39" y="307.77" width="86.17" height="6.57" transform="translate(-264.01 3.48) rotate(-6.05)" fill="#fff"/><rect x="704.78" y="319.53" width="138.75" height="6.57" transform="translate(-265.1 6.46) rotate(-6.05)" fill="#fff"/><rect x="733.11" y="338.4" width="86.17" height="7.3" rx="3.09" ry="3.09" transform="translate(-267.12 6.78) rotate(-6.05)" opacity="0.2"/><circle cx="625.29" cy="473.71" r="15.34" transform="translate(-281.83 -8.39) rotate(-6.05)" fill="#69f0ae"/><rect x="667.96" y="520.81" width="86.17" height="6.57" transform="translate(-286.66 0.93) rotate(-6.05)" fill="#bdbdbd"/><rect x="670.73" y="546.96" width="86.17" height="6.57" transform="translate(-289.4 1.36) rotate(-6.05)" fill="#f5f5f5"/><rect x="668.96" y="526.57" width="224.92" height="6.57" transform="translate(-286.88 8.38) rotate(-6.05)" fill="#e0e0e0"/><circle cx="631.99" cy="536.88" r="15.34" transform="translate(-288.45 -7.33) rotate(-6.05)" fill="#e0e0e0"/><rect x="674.65" y="583.99" width="86.17" height="6.57" transform="translate(-293.28 1.98) rotate(-6.05)" fill="#bdbdbd"/><rect x="677.42" y="610.13" width="86.17" height="6.57" transform="translate(-296.02 2.42) rotate(-6.05)" fill="#f5f5f5"/><rect x="675.65" y="589.75" width="224.92" height="6.57" transform="translate(-293.5 9.43) rotate(-6.05)" fill="#e0e0e0"/><circle cx="638.68" cy="600.06" r="15.34" transform="translate(-295.07 -6.28) rotate(-6.05)" fill="#e0e0e0"/><path d="M595.69,341.12A42.28,42.28,0,1,0,647.23,295l1.28,10.82A14.36,14.36,0,0,1,636,321.67h0a14.36,14.36,0,0,1-15.9-12.54l-1.28-10.82A42.3,42.3,0,0,0,595.69,341.12Z" transform="translate(-235.39 -76.93)" fill="url(#e9a0bbc5-d046-4610-9b74-eda9798afd67)"/><path d="M679.33,327.79a42.28,42.28,0,1,0-52.09,45.54l-1.15-10.83a14.36,14.36,0,0,1,12.73-15.75h0a14.36,14.36,0,0,1,15.75,12.73l1.15,10.83A42.3,42.3,0,0,0,679.33,327.79Z" transform="translate(-235.39 -76.93)" fill="#3f51b5"/><circle cx="636.7" cy="326.46" r="16.25" transform="translate(-266.25 -8.01) rotate(-6.05)" fill="#fff" stroke="#fff" stroke-miterlimit="10"/><path d="M638.82,346.75h0a14.36,14.36,0,0,0-12.73,15.75l1.15,10.83a42.44,42.44,0,0,0,28.48-3l-1.15-10.83A14.36,14.36,0,0,0,638.82,346.75Z" transform="translate(-235.39 -76.93)" fill="#fff" stroke="#fff" stroke-miterlimit="10"/><path d="M620.3,327.29a15.77,15.77,0,0,1-2.59-7.95,10.93,10.93,0,0,1,2.8-7.75c2.14-2.26,5.26-3.31,8.32-3.88S635,307,638,306a19.44,19.44,0,0,0,11.46-9.68,26.14,26.14,0,0,1,.69,7.12,8.81,8.81,0,0,1-3.06,6.27c2.33-1.4,2.35,1.29,2,2.95,1.37,1.34,4.35,1.27,4.71,3.16a12,12,0,0,1,0,5.68c-.56,1.83.57,4.84-1.32,5.17" transform="translate(-235.39 -76.93)" fill="#fff" stroke="#fff" stroke-miterlimit="10"/><path d="M647.93,309.26s11.38-.21,5.13,17.38" transform="translate(-235.39 -76.93)" fill="#fff"/><rect x="220.3" y="0.4" width="325.25" height="427.62" fill="url(#d89d3977-de30-46d1-ab57-98fa636459b9)"/><rect x="219.92" width="326" height="162.99" fill="url(#1e925d76-3047-4c1e-82a0-04113f14e226)"/><rect x="224.46" y="3.71" width="316.93" height="417.67" fill="#f5f5f5"/><rect x="224.1" y="3.32" width="317.66" height="159.19" fill="#3f51b5"/><rect x="290.91" y="207.42" width="86.17" height="6.57" fill="#bdbdbd"/><rect x="290.91" y="233.71" width="86.17" height="6.57" fill="#f5f5f5"/><rect x="290.91" y="220.57" width="224.92" height="6.57" fill="#69f0ae"/><rect x="348.6" y="62.84" width="86.17" height="6.57" fill="#fff"/><rect x="348.6" y="77.44" width="138.75" height="6.57" fill="#fff"/><rect x="374.89" y="96.43" width="86.17" height="7.3" rx="3.09" ry="3.09" opacity="0.2"/><circle cx="254.04" cy="215.09" r="15.34" fill="#69f0ae"/><rect x="290.91" y="270.95" width="86.17" height="6.57" fill="#bdbdbd"/><rect x="290.91" y="297.24" width="86.17" height="6.57" fill="#f5f5f5"/><rect x="290.91" y="284.1" width="224.92" height="6.57" fill="#e0e0e0"/><circle cx="254.04" cy="278.62" r="15.34" fill="#e0e0e0"/><rect x="290.91" y="334.49" width="86.17" height="6.57" fill="#bdbdbd"/><rect x="290.91" y="360.77" width="86.17" height="6.57" fill="#f5f5f5"/><rect x="290.91" y="347.63" width="224.92" height="6.57" fill="#e0e0e0"/><circle cx="254.04" cy="342.15" r="15.34" fill="#e0e0e0"/><path d="M474,157.06a42.28,42.28,0,1,0,56.12-40.48l.13,10.89A14.36,14.36,0,0,1,516.07,142h0a14.36,14.36,0,0,1-14.49-14.14l-.13-10.89A42.3,42.3,0,0,0,474,157.06Z" transform="translate(-235.39 -76.93)" fill="url(#9a56d00c-164c-4fec-8f17-f5f893f4fff9)"/><path d="M558.55,152.61a42.28,42.28,0,1,0-56.6,39.8V181.51a14.36,14.36,0,0,1,14.32-14.32h0a14.36,14.36,0,0,1,14.32,14.32v10.89A42.3,42.3,0,0,0,558.55,152.61Z" transform="translate(-235.39 -76.93)" fill="#3f51b5"/><circle cx="280.9" cy="69.87" r="16.25" fill="#fff" stroke="#fff" stroke-miterlimit="10"/><path d="M516.26,167.19h0a14.36,14.36,0,0,0-14.32,14.32v10.89a42.44,42.44,0,0,0,28.64,0V181.51A14.36,14.36,0,0,0,516.26,167.19Z" transform="translate(-235.39 -76.93)" fill="#fff" stroke="#fff" stroke-miterlimit="10"/><path d="M499.9,145.89a15.77,15.77,0,0,1-1.73-8.18,10.93,10.93,0,0,1,3.6-7.42c2.37-2,5.58-2.73,8.68-3s6.24-.1,9.3-.7a19.44,19.44,0,0,0,12.41-8.42,26.14,26.14,0,0,1-.07,7.15,8.81,8.81,0,0,1-3.7,5.91c2.47-1.14,2.2,1.53,1.67,3.14,1.22,1.48,4.2,1.72,4.35,3.64a12,12,0,0,1-.62,5.65c-.75,1.76.05,4.87-1.86,5" transform="translate(-235.39 -76.93)" fill="#fff" stroke="#fff" stroke-miterlimit="10"/><path d="M529.27,130.88s11.34,1,3.27,17.82" transform="translate(-235.39 -76.93)" fill="#fff"/><polygon points="190.59 304.74 119.42 254.91 20.88 254.91 20.88 304.74 20.88 329.15 20.88 746.14 636.74 746.14 636.74 304.74 190.59 304.74" fill="url(#595bce0a-5d70-43e8-a094-99f33f4517de)"/><polyline points="26.15 309.78 26.15 333.48 26.15 738.25 632.52 738.25 632.52 309.78 193.25 309.78" fill="#fff"/><polyline points="193.25 309.78 123.17 261.41 26.15 261.41 26.15 309.78" fill="#bdbdbd"/><text x="-235.39" y="-76.93"></text><rect x="162.34" y="373.01" width="334" height="302" fill="url(#7d63bf16-77e8-4c09-b275-41a64fa57a97)"/><rect x="166.88" y="375.21" width="326.42" height="294.31" fill="#fff"/><rect x="268.19" y="595.49" width="128.34" height="10.51" fill="#bdbdbd"/><rect x="189.87" y="616.52" width="280.44" height="10.51" fill="#e0e0e0"/><rect x="189.87" y="637.55" width="280.44" height="10.51" fill="#e0e0e0"/><path d="M485.62,564.67a79.84,79.84,0,1,0,106-76.43l.25,20.57a27.11,27.11,0,0,1-26.7,27.36h0a27.11,27.11,0,0,1-27.36-26.7l-.25-20.57A79.87,79.87,0,0,0,485.62,564.67Z" transform="translate(-235.39 -76.93)" fill="url(#cafffc46-2bab-4c9b-8a17-f57a9c7cb665)"/><path d="M645.32,556.28a79.84,79.84,0,1,0-106.87,75.14V610.85a27.11,27.11,0,0,1,27-27h0a27.11,27.11,0,0,1,27,27v20.57A79.87,79.87,0,0,0,645.32,556.28Z" transform="translate(-235.39 -76.93)" fill="#bdbdbd"/><rect x="323.18" y="488.01" width="9.6" height="33.85" rx="4.8" ry="4.8" fill="#fff" stroke="#fff" stroke-miterlimit="10"/><circle cx="328.03" cy="461.87" r="30.69" fill="#fff" stroke="#fff" stroke-miterlimit="10"/><path d="M563.37,577.31h0a27.11,27.11,0,0,0-27,27v20.57a80.13,80.13,0,0,0,54.07,0V604.35A27.11,27.11,0,0,0,563.37,577.31Z" transform="translate(-235.39 -76.93)" fill="#fff" stroke="#fff" stroke-miterlimit="10"/><path d="M532.47,537.1a29.77,29.77,0,0,1-3.27-15.44,20.64,20.64,0,0,1,6.8-14c4.47-3.81,10.53-5.16,16.39-5.63s11.79-.19,17.55-1.32a36.69,36.69,0,0,0,23.43-15.89c.37,4.5.74,9.07-.13,13.51s-3.15,8.79-7,11.16c4.66-2.16,4.15,2.9,3.14,5.93,2.31,2.79,7.92,3.25,8.21,6.86s.24,7.34-1.17,10.67.1,9.19-3.5,9.45" transform="translate(-235.39 -76.93)" fill="#fff" stroke="#fff" stroke-miterlimit="10"/><path d="M587.94,508.75s21.41,1.87,6.17,33.65" transform="translate(-235.39 -76.93)" fill="#fff"/></svg>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="theme-color" content="#000000" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link
href="https://fonts.googleapis.com/css?family=Roboto+Mono|Roboto+Slab|Roboto:300,400,500,700"
rel="stylesheet"
/>
<title>React Material Dashboard</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
import React, { Component } from 'react';
import { Router } from 'react-router-dom';
import { createBrowserHistory } from 'history';
import { Chart } from 'react-chartjs-2';
import { ThemeProvider } from '@material-ui/styles';
import validate from 'validate.js';
import { chartjs } from './helpers';
import theme from './theme';
import 'react-perfect-scrollbar/dist/css/styles.css';
import './assets/scss/index.scss';
import validators from './common/validators';
import Routes from './Routes';
const browserHistory = createBrowserHistory();
Chart.helpers.extend(Chart.elements.Rectangle.prototype, {
draw: chartjs.draw
});
validate.validators = {
...validate.validators,
...validators
};
export default class App extends Component {
render() {
return (
<ThemeProvider theme={theme}>
<Router history={browserHistory}>
<Routes />
</Router>
</ThemeProvider>
);
}
}
import React from 'react';
import { Switch, Redirect } from 'react-router-dom';
import { RouteWithLayout } from './components';
import { Main as MainLayout, Minimal as MinimalLayout } from './layouts';
import {
Dashboard as DashboardView,
ProductList as ProductListView,
UserList as UserListView,
Typography as TypographyView,
Icons as IconsView,
Account as AccountView,
Settings as SettingsView,
SignUp as SignUpView,
SignIn as SignInView,
NotFound as NotFoundView
} from './views';
const Routes = () => {
return (
<Switch>
<Redirect
exact
from="/"
to="/dashboard"
/>
<RouteWithLayout
component={DashboardView}
exact
layout={MainLayout}
path="/dashboard"
/>
<RouteWithLayout
component={UserListView}
exact
layout={MainLayout}
path="/users"
/>
<RouteWithLayout
component={ProductListView}
exact
layout={MainLayout}
path="/products"
/>
<RouteWithLayout
component={TypographyView}
exact
layout={MainLayout}
path="/typography"
/>
<RouteWithLayout
component={IconsView}
exact
layout={MainLayout}
path="/icons"
/>
<RouteWithLayout
component={AccountView}
exact
layout={MainLayout}
path="/account"
/>
<RouteWithLayout
component={SettingsView}
exact
layout={MainLayout}
path="/settings"
/>
<RouteWithLayout
component={SignUpView}
exact
layout={MinimalLayout}
path="/sign-up"
/>
<RouteWithLayout
component={SignInView}
exact
layout={MinimalLayout}
path="/sign-in"
/>
<RouteWithLayout
component={NotFoundView}
exact
layout={MinimalLayout}
path="/not-found"
/>
<Redirect to="/not-found" />
</Switch>
);
};
export default Routes;
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
height: 100%;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
background-color: #f4f6f8;
height: 100%;
}
a {
text-decoration: none;
}
#root {
height: 100%;
}
const checked = (value, options) => {
if (value !== true) {
return options.message || 'must be checked';
}
};
export default {
checked
};
import React from 'react';
import { Route } from 'react-router-dom';
import PropTypes from 'prop-types';
const RouteWithLayout = props => {
const { layout: Layout, component: Component, ...rest } = props;
return (
<Route
{...rest}
render={matchProps => (
<Layout>
<Component {...matchProps} />
</Layout>
)}
/>
);
};
RouteWithLayout.propTypes = {
component: PropTypes.any.isRequired,
layout: PropTypes.any.isRequired,
path: PropTypes.string
};
export default RouteWithLayout;
export { default } from './RouteWithLayout';
import React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { makeStyles } from '@material-ui/styles';
import { Paper, Input } from '@material-ui/core';
import SearchIcon from '@material-ui/icons/Search';
const useStyles = makeStyles(theme => ({
root: {
borderRadius: '4px',
alignItems: 'center',
padding: theme.spacing(1),
display: 'flex',
flexBasis: 420
},
icon: {
marginRight: theme.spacing(1),
color: theme.palette.text.secondary
},
input: {
flexGrow: 1,
fontSize: '14px',
lineHeight: '16px',
letterSpacing: '-0.05px'
}
}));
const SearchInput = props => {
const { className, onChange, style, ...rest } = props;
const classes = useStyles();
return (
<Paper
{...rest}
className={clsx(classes.root, className)}
style={style}
>
<SearchIcon className={classes.icon} />
<Input
{...rest}
className={classes.input}
disableUnderline
onChange={onChange}
/>
</Paper>
);
};
SearchInput.propTypes = {
className: PropTypes.string,
onChange: PropTypes.func,
style: PropTypes.object
};
export default SearchInput;
export { default } from './SearchInput';
import React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { makeStyles } from '@material-ui/styles';
const useStyles = makeStyles(theme => ({
root: {
display: 'inline-block',
borderRadius: '50%',
flexGrow: 0,
flexShrink: 0
},
sm: {
height: theme.spacing(1),
width: theme.spacing(1)
},
md: {
height: theme.spacing(2),
width: theme.spacing(2)
},
lg: {
height: theme.spacing(3),
width: theme.spacing(3)
},
neutral: {
backgroundColor: theme.palette.neutral
},
primary: {
backgroundColor: theme.palette.primary.main
},
info: {
backgroundColor: theme.palette.info.main
},
warning: {
backgroundColor: theme.palette.warning.main
},
danger: {
backgroundColor: theme.palette.error.main
},
success: {
backgroundColor: theme.palette.success.main
}
}));
const StatusBullet = props => {
const { className, size, color, ...rest } = props;
const classes = useStyles();
return (
<span
{...rest}
className={clsx(
{
[classes.root]: true,
[classes[size]]: size,
[classes[color]]: color
},
className
)}
/>
);
};
StatusBullet.propTypes = {
className: PropTypes.string,
color: PropTypes.oneOf([
'neutral',
'primary',
'info',
'success',
'warning',
'danger'
]),
size: PropTypes.oneOf(['sm', 'md', 'lg'])
};
StatusBullet.defaultProps = {
size: 'md',
color: 'default'
};
export default StatusBullet;
export { default } from './StatusBullet'
\ No newline at end of file
export { default as SearchInput } from './SearchInput';
export { default as StatusBullet } from './StatusBullet';
export { default as RouteWithLayout } from './RouteWithLayout';
// ChartJS extension rounded bar chart
// https://codepen.io/jedtrow/full/ygRYgo
function draw() {
const { ctx } = this._chart;
const vm = this._view;
let { borderWidth } = vm;
let left;
let right;
let top;
let bottom;
let signX;
let signY;
let borderSkipped;
let radius;
// If radius is less than 0 or is large enough to cause drawing errors a max
// radius is imposed. If cornerRadius is not defined set it to 0.
let { cornerRadius } = this._chart.config.options;
if (cornerRadius < 0) {
cornerRadius = 0;
}
if (typeof cornerRadius === 'undefined') {
cornerRadius = 0;
}
if (!vm.horizontal) {
// bar
left = vm.x - vm.width / 2;
right = vm.x + vm.width / 2;
top = vm.y;
bottom = vm.base;
signX = 1;
signY = bottom > top ? 1 : -1;
borderSkipped = vm.borderSkipped || 'bottom';
} else {
// horizontal bar
left = vm.base;
right = vm.x;
top = vm.y - vm.height / 2;
bottom = vm.y + vm.height / 2;
signX = right > left ? 1 : -1;
signY = 1;
borderSkipped = vm.borderSkipped || 'left';
}
// Canvas doesn't allow us to stroke inside the width so we can
// adjust the sizes to fit if we're setting a stroke on the line
if (borderWidth) {
// borderWidth shold be less than bar width and bar height.
const barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
borderWidth = borderWidth > barSize ? barSize : borderWidth;
const halfStroke = borderWidth / 2;
// Adjust borderWidth when bar top position is near vm.base(zero).
const borderLeft =
left + (borderSkipped !== 'left' ? halfStroke * signX : 0);
const borderRight =
right + (borderSkipped !== 'right' ? -halfStroke * signX : 0);
const borderTop = top + (borderSkipped !== 'top' ? halfStroke * signY : 0);
const borderBottom =
bottom + (borderSkipped !== 'bottom' ? -halfStroke * signY : 0);
// not become a vertical line?
if (borderLeft !== borderRight) {
top = borderTop;
bottom = borderBottom;
}
// not become a horizontal line?
if (borderTop !== borderBottom) {
left = borderLeft;
right = borderRight;
}
}
ctx.beginPath();
ctx.fillStyle = vm.backgroundColor;
ctx.strokeStyle = vm.borderColor;
ctx.lineWidth = borderWidth;
// Corner points, from bottom-left to bottom-right clockwise
// | 1 2 |
// | 0 3 |
const corners = [[left, bottom], [left, top], [right, top], [right, bottom]];
// Find first (starting) corner with fallback to 'bottom'
const borders = ['bottom', 'left', 'top', 'right'];
let startCorner = borders.indexOf(borderSkipped, 0);
if (startCorner === -1) {
startCorner = 0;
}
function cornerAt(index) {
return corners[(startCorner + index) % 4];
}
// Draw rectangle from 'startCorner'
let corner = cornerAt(0);
ctx.moveTo(corner[0], corner[1]);
for (let i = 1; i < 4; i += 1) {
corner = cornerAt(i);
let nextCornerId = i + 1;
if (nextCornerId === 4) {
nextCornerId = 0;
}
const width = corners[2][0] - corners[1][0];
const height = corners[0][1] - corners[1][1];
const x = corners[1][0];
const y = corners[1][1];
radius = cornerRadius;
// Fix radius being too large
if (radius > Math.abs(height) / 2) {
radius = Math.floor(Math.abs(height) / 2);
}
if (radius > Math.abs(width) / 2) {
radius = Math.floor(Math.abs(width) / 2);
}
if (height < 0) {
// Negative values in a standard bar chart
const xTl = x;
const xTr = x + width;
const yTl = y + height;
const yTr = y + height;
const xBl = x;
const xBr = x + width;
const yBl = y;
const yBr = y;
// Draw
ctx.moveTo(xBl + radius, yBl);
ctx.lineTo(xBr - radius, yBr);
ctx.quadraticCurveTo(xBr, yBr, xBr, yBr - radius);
ctx.lineTo(xTr, yTr + radius);
ctx.quadraticCurveTo(xTr, yTr, xTr - radius, yTr);
ctx.lineTo(xTl + radius, yTl);
ctx.quadraticCurveTo(xTl, yTl, xTl, yTl + radius);
ctx.lineTo(xBl, yBl - radius);
ctx.quadraticCurveTo(xBl, yBl, xBl + radius, yBl);
} else if (width < 0) {
// Negative values in a horizontal bar chart
const xTl = x + width;
const xTr = x;
const yTl = y;
const yTr = y;
const xBl = x + width;
const xBr = x;
const yBl = y + height;
const yBr = y + height;
// Draw
ctx.moveTo(xBl + radius, yBl);
ctx.lineTo(xBr - radius, yBr);
ctx.quadraticCurveTo(xBr, yBr, xBr, yBr - radius);
ctx.lineTo(xTr, yTr + radius);
ctx.quadraticCurveTo(xTr, yTr, xTr - radius, yTr);
ctx.lineTo(xTl + radius, yTl);
ctx.quadraticCurveTo(xTl, yTl, xTl, yTl + radius);
ctx.lineTo(xBl, yBl - radius);
ctx.quadraticCurveTo(xBl, yBl, xBl + radius, yBl);
} else {
// Positive Value
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(
x + width,
y + height,
x + width - radius,
y + height
);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
}
}
ctx.fill();
if (borderWidth) {
ctx.stroke();
}
}
export default {
draw
};
export default (name = '') =>
name
.replace(/\s+/, ' ')
.split(' ')
.slice(0, 2)
.map(v => v && v[0].toUpperCase())
.join('');
export { default as chartjs } from './chartjs';
export { default as getInitials } from './getInitials';
import React from 'react';
// Material components
import { SvgIcon } from '@material-ui/core';
export default function Facebook(props) {
return (
<SvgIcon {...props}>
<path d="M9.53144612,22.005 L9.53144612,13.0552149 L6.44166667,13.0552149 L6.44166667,9.49875 L9.53144612,9.49875 L9.53144612,6.68484375 C9.53144612,5.19972656 9.95946769,4.04680661 10.8155103,3.22608401 C11.6715529,2.4053613 12.808485,1.995 14.2263057,1.995 C15.3766134,1.995 16.3129099,2.04710915 17.0351961,2.15132812 L17.0351961,5.3169726 L15.1090998,5.3169726 C14.3868137,5.3169726 13.8919142,5.47330073 13.6244006,5.78595698 C13.4103902,6.04650407 13.3033846,6.46337874 13.3033846,7.03658198 L13.3033846,9.49875 L16.71418,9.49875 L16.2326559,13.0552149 L13.3033846,13.0552149 L13.3033846,22.005 L9.53144612,22.005 Z" />
</SvgIcon>
);
}
import React from 'react';
// Material components
import { SvgIcon } from '@material-ui/core';
export default function Google(props) {
return (
<SvgIcon {...props}>
<path d="M21,12.2177419 C21,13.9112905 20.6311475,15.4233869 19.8934426,16.7540323 C19.1557377,18.0846776 18.1168031,19.1249998 16.7766393,19.875 C15.4364756,20.6250002 13.8934424,21 12.147541,21 C10.4999998,21 8.97540984,20.5947579 7.57377049,19.7842742 C6.17213115,18.9737905 5.05942604,17.8790323 4.23565574,16.5 C3.41188543,15.1209677 3,13.6209679 3,12 C3,10.3790321 3.41188543,8.87903226 4.23565574,7.5 C5.05942604,6.12096774 6.17213115,5.02620949 7.57377049,4.21572581 C8.97540984,3.40524212 10.4999998,3 12.147541,3 C14.5327871,3 16.5737705,3.78629051 18.2704918,5.35887097 L15.7991803,7.71774194 C15.0122953,6.96774175 14.0655738,6.52016129 12.9590164,6.375 C11.9262295,6.22983871 10.9057375,6.375 9.89754098,6.81048387 C8.88934445,7.24596774 8.07786904,7.89919355 7.46311475,8.77016129 C6.79918033,9.71370968 6.46721311,10.7903228 6.46721311,12 C6.46721311,13.0403228 6.72540984,13.9899192 7.24180328,14.8487903 C7.75819672,15.7076615 8.4467215,16.3971776 9.30737705,16.9173387 C10.1680326,17.4374998 11.1147541,17.6975806 12.147541,17.6975806 C13.2540984,17.6975806 14.2254096,17.455645 15.0614754,16.9717742 C15.7254098,16.5846772 16.2786885,16.0645161 16.7213115,15.4112903 C17.0409838,14.8790321 17.2499998,14.3467744 17.3483607,13.8145161 L12.147541,13.8145161 L12.147541,10.6935484 L20.852459,10.6935484 C20.9508199,11.2258066 21,11.7338712 21,12.2177419 Z" />
</SvgIcon>
);
}
export { default as Facebook } from './Facebook';
export { default as Google } from './Google';
import React from 'react';
import ReactDOM from 'react-dom';
import * as serviceWorker from './serviceWorker';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { makeStyles, useTheme } from '@material-ui/styles';
import { useMediaQuery } from '@material-ui/core';
import { Sidebar, Topbar, Footer } from './components';
const useStyles = makeStyles(theme => ({
root: {
paddingTop: 56,
height: '100%',
[theme.breakpoints.up('sm')]: {
paddingTop: 64
}
},
shiftContent: {
paddingLeft: 240
},
content: {
height: '100%'
}
}));
const Main = props => {
const { children } = props;
const classes = useStyles();
const theme = useTheme();
const isDesktop = useMediaQuery(theme.breakpoints.up('lg'), {
defaultMatches: true
});
const [openSidebar, setOpenSidebar] = useState(false);
const handleSidebarOpen = () => {
setOpenSidebar(true);
};
const handleSidebarClose = () => {
setOpenSidebar(false);
};
const shouldOpenSidebar = isDesktop ? true : openSidebar;
return (
<div
className={clsx({
[classes.root]: true,
[classes.shiftContent]: isDesktop
})}
>
<Topbar onSidebarOpen={handleSidebarOpen} />
<Sidebar
onClose={handleSidebarClose}
open={shouldOpenSidebar}
variant={isDesktop ? 'persistent' : 'temporary'}
/>
<main className={classes.content}>
{children}
<Footer />
</main>
</div>
);
};
Main.propTypes = {
children: PropTypes.node
};
export default Main;
import React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { makeStyles } from '@material-ui/styles';
import { Typography, Link } from '@material-ui/core';
const useStyles = makeStyles(theme => ({
root: {
padding: theme.spacing(4)
}
}));
const Footer = props => {
const { className, ...rest } = props;
const classes = useStyles();
return (
<div
{...rest}
className={clsx(classes.root, className)}
>
<Typography variant="body1">
&copy;{' '}
<Link
component="a"
href="https://devias.io/"
target="_blank"
>
Devias IO
</Link>
. 2019
</Typography>
<Typography variant="caption">
Created with love for the environment. By designers and developers who
love to work together in offices!
</Typography>
</div>
);
};
Footer.propTypes = {
className: PropTypes.string
};
export default Footer;
import React from 'react';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/styles';
import { Divider, Drawer } from '@material-ui/core';
import DashboardIcon from '@material-ui/icons/Dashboard';
import PeopleIcon from '@material-ui/icons/People';
import ShoppingBasketIcon from '@material-ui/icons/ShoppingBasket';
import TextFieldsIcon from '@material-ui/icons/TextFields';
import ImageIcon from '@material-ui/icons/Image';
import AccountBoxIcon from '@material-ui/icons/AccountBox';
import SettingsIcon from '@material-ui/icons/Settings';
import LockOpenIcon from '@material-ui/icons/LockOpen';
import { Profile, SidebarNav, UpgradePlan } from './components';
const useStyles = makeStyles(theme => ({
drawer: {
width: 240,
[theme.breakpoints.up('lg')]: {
marginTop: 64,
height: 'calc(100% - 64px)'
}
},
root: {
backgroundColor: theme.palette.white,
display: 'flex',
flexDirection: 'column',
height: '100%',
padding: theme.spacing(2)
},
divider: {
margin: theme.spacing(2, 0)
},
nav: {
marginBottom: theme.spacing(2)
}
}));
const Sidebar = props => {
const { open, variant, onClose, className, ...rest } = props;
const classes = useStyles();
const pages = [
{
title: 'Dashboard',
href: '/dashboard',
icon: <DashboardIcon />
},
{
title: 'Users',
href: '/users',
icon: <PeopleIcon />
},
{
title: 'Products',
href: '/products',
icon: <ShoppingBasketIcon />
},
{
title: 'Authentication',
href: '/sign-in',
icon: <LockOpenIcon />
},
{
title: 'Typography',
href: '/typography',
icon: <TextFieldsIcon />
},
{
title: 'Icons',
href: '/icons',
icon: <ImageIcon />
},
{
title: 'Account',
href: '/account',
icon: <AccountBoxIcon />
},
{
title: 'Settings',
href: '/settings',
icon: <SettingsIcon />
}
];
return (
<Drawer
anchor="left"
classes={{ paper: classes.drawer }}
onClose={onClose}
open={open}
variant={variant}
>
<div
{...rest}
className={clsx(classes.root, className)}
>
<Profile />
<Divider className={classes.divider} />
<SidebarNav
className={classes.nav}
pages={pages}
/>
<UpgradePlan />
</div>
</Drawer>
);
};
Sidebar.propTypes = {
className: PropTypes.string,
onClose: PropTypes.func,
open: PropTypes.bool.isRequired,
variant: PropTypes.string.isRequired
};
export default Sidebar;
import React from 'react';
import { Link as RouterLink } from 'react-router-dom';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/styles';
import { Avatar, Typography } from '@material-ui/core';
const useStyles = makeStyles(theme => ({
root: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
minHeight: 'fit-content'
},
avatar: {
width: 60,
height: 60
},
name: {
marginTop: theme.spacing(1)
}
}));
const Profile = props => {
const { className, ...rest } = props;
const classes = useStyles();
const user = {
name: 'Shen Zhi',
avatar: '/images/avatars/avatar_11.png',
bio: 'Brain Director'
};
return (
<div
{...rest}
className={clsx(classes.root, className)}
>
<Avatar
alt="Person"
className={classes.avatar}
component={RouterLink}
src={user.avatar}
to="/settings"
/>
<Typography
className={classes.name}
variant="h4"
>
{user.name}
</Typography>
<Typography variant="body2">{user.bio}</Typography>
</div>
);
};
Profile.propTypes = {
className: PropTypes.string
};
export default Profile;
/* eslint-disable react/no-multi-comp */
/* eslint-disable react/display-name */
import React, { forwardRef } from 'react';
import { NavLink as RouterLink } from 'react-router-dom';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/styles';
import { List, ListItem, Button, colors } from '@material-ui/core';
const useStyles = makeStyles(theme => ({
root: {},
item: {
display: 'flex',
paddingTop: 0,
paddingBottom: 0
},
button: {
color: colors.blueGrey[800],
padding: '10px 8px',
justifyContent: 'flex-start',
textTransform: 'none',
letterSpacing: 0,
width: '100%',
fontWeight: theme.typography.fontWeightMedium
},
icon: {
color: theme.palette.icon,
width: 24,
height: 24,
display: 'flex',
alignItems: 'center',
marginRight: theme.spacing(1)
},
active: {
color: theme.palette.primary.main,
fontWeight: theme.typography.fontWeightMedium,
'& $icon': {
color: theme.palette.primary.main
}
}
}));
const CustomRouterLink = forwardRef((props, ref) => (
<div
ref={ref}
style={{ flexGrow: 1 }}
>
<RouterLink {...props} />
</div>
));
const SidebarNav = props => {
const { pages, className, ...rest } = props;
const classes = useStyles();
return (
<List
{...rest}
className={clsx(classes.root, className)}
>
{pages.map(page => (
<ListItem
className={classes.item}
disableGutters
key={page.title}
>
<Button
activeClassName={classes.active}
className={classes.button}
component={CustomRouterLink}
to={page.href}
>
<div className={classes.icon}>{page.icon}</div>
{page.title}
</Button>
</ListItem>
))}
</List>
);
};
SidebarNav.propTypes = {
className: PropTypes.string,
pages: PropTypes.array.isRequired
};
export default SidebarNav;
import React from 'react';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/styles';
import { Typography, Button, colors } from '@material-ui/core';
const useStyles = makeStyles(theme => ({
root: {
backgroundColor: colors.grey[50]
},
media: {
paddingTop: theme.spacing(2),
height: 80,
textAlign: 'center',
'& > img': {
height: '100%',
width: 'auto'
}
},
content: {
padding: theme.spacing(1, 2)
},
actions: {
padding: theme.spacing(1, 2),
display: 'flex',
justifyContent: 'center'
}
}));
const UpgradePlan = props => {
const { className, ...rest } = props;
const classes = useStyles();
return (
<div
{...rest}
className={clsx(classes.root, className)}
>
<div className={classes.media}>
<img
alt="Upgrade to PRO"
src="/images/undraw_resume_folder_2_arse.svg"
/>
</div>
<div className={classes.content}>
<Typography
align="center"
gutterBottom
variant="h6"
>
Upgrade to PRO
</Typography>
<Typography
align="center"
variant="body2"
>
Upgrade to Devias Kit PRO and get even more components
</Typography>
</div>
<div className={classes.actions}>
<Button
color="primary"
component="a"
href="https://devias.io/products/devias-kit-pro"
variant="contained"
>
Upgrade
</Button>
</div>
</div>
);
};
UpgradePlan.propTypes = {
className: PropTypes.string
};
export default UpgradePlan;
export { default as Profile } from './Profile';
export { default as SidebarNav } from './SidebarNav';
export { default as UpgradePlan } from './UpgradePlan';
import React, { useState } from 'react';
import { Link as RouterLink } from 'react-router-dom';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/styles';
import { AppBar, Toolbar, Badge, Hidden, IconButton } from '@material-ui/core';
import MenuIcon from '@material-ui/icons/Menu';
import NotificationsIcon from '@material-ui/icons/NotificationsOutlined';
import InputIcon from '@material-ui/icons/Input';
const useStyles = makeStyles(theme => ({
root: {
boxShadow: 'none'
},
flexGrow: {
flexGrow: 1
},
signOutButton: {
marginLeft: theme.spacing(1)
}
}));
const Topbar = props => {
const { className, onSidebarOpen, ...rest } = props;
const classes = useStyles();
const [notifications] = useState([]);
return (
<AppBar
{...rest}
className={clsx(classes.root, className)}
>
<Toolbar>
<RouterLink to="/">
<img
alt="Logo"
src="/images/logos/logo--white.svg"
/>
</RouterLink>
<div className={classes.flexGrow} />
<Hidden mdDown>
<IconButton color="inherit">
<Badge
badgeContent={notifications.length}
color="primary"
variant="dot"
>
<NotificationsIcon />
</Badge>
</IconButton>
<IconButton
className={classes.signOutButton}
color="inherit"
>
<InputIcon />
</IconButton>
</Hidden>
<Hidden lgUp>
<IconButton
color="inherit"
onClick={onSidebarOpen}
>
<MenuIcon />
</IconButton>
</Hidden>
</Toolbar>
</AppBar>
);
};
Topbar.propTypes = {
className: PropTypes.string,
onSidebarOpen: PropTypes.func
};
export default Topbar;
export { default as Footer } from './Footer';
export { default as Sidebar } from './Sidebar';
export { default as Topbar } from './Topbar';
export { default } from './Main';
import React from 'react';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/styles';
import { Topbar } from './components';
const useStyles = makeStyles(() => ({
root: {
paddingTop: 64,
height: '100%'
},
content: {
height: '100%'
}
}));
const Minimal = props => {
const { children } = props;
const classes = useStyles();
return (
<div className={classes.root}>
<Topbar />
<main className={classes.content}>{children}</main>
</div>
);
};
Minimal.propTypes = {
children: PropTypes.node,
className: PropTypes.string
};
export default Minimal;
import React from 'react';
import { Link as RouterLink } from 'react-router-dom';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/styles';
import { AppBar, Toolbar } from '@material-ui/core';
const useStyles = makeStyles(() => ({
root: {
boxShadow: 'none'
}
}));
const Topbar = props => {
const { className, ...rest } = props;
const classes = useStyles();
return (
<AppBar
{...rest}
className={clsx(classes.root, className)}
color="primary"
position="fixed"
>
<Toolbar>
<RouterLink to="/">
<img
alt="Logo"
src="/images/logos/logo--white.svg"
/>
</RouterLink>
</Toolbar>
</AppBar>
);
};
Topbar.propTypes = {
className: PropTypes.string
};
export default Topbar;
export { default as Topbar } from './Topbar';
export { default } from './Minimal';
export { default as Main } from './Main';
export { default as Minimal } from './Minimal';
// This optional code is used to register a service worker.
// register() is not called by default.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on subsequent visits to a page, after all the
// existing tabs open on the page have been closed, since previously cached
// resources are updated in the background.
// To learn more about the benefits of this model and instructions on how to
// opt-in, read http://bit.ly/CRA-PWA
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
export function register(config) {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return;
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit http://bit.ly/CRA-PWA'
);
});
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config);
}
});
}
}
function registerValidSW(swUrl, config) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed. See http://bit.ly/CRA-PWA.'
);
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl, config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
}
}
import { createMuiTheme } from '@material-ui/core';
import palette from './palette';
import typography from './typography';
import overrides from './overrides';
const theme = createMuiTheme({
palette,
typography,
overrides,
zIndex: {
appBar: 1200,
drawer: 1100
}
});
export default theme;
export default {
contained: {
boxShadow:
'0 1px 1px 0 rgba(0,0,0,0.14), 0 2px 1px -1px rgba(0,0,0,0.12), 0 1px 3px 0 rgba(0,0,0,0.20)',
backgroundColor: '#FFFFFF'
}
};
import palette from '../palette';
export default {
root: {
color: palette.icon,
'&:hover': {
backgroundColor: 'rgba(0, 0, 0, 0.03)'
}
}
};
export default {
elevation1: {
boxShadow: '0 0 0 1px rgba(63,63,68,0.05), 0 1px 3px 0 rgba(63,63,68,0.15)'
}
};
import palette from '../palette';
import typography from '../typography';
export default {
root: {
...typography.body1,
borderBottom: `1px solid ${palette.divider}`
}
};
import { colors } from '@material-ui/core';
export default {
root: {
backgroundColor: colors.grey[50]
}
};
import palette from '../palette';
export default {
root: {
'&$selected': {
backgroundColor: palette.background.default
},
'&$hover': {
'&:hover': {
backgroundColor: palette.background.default
}
}
}
};
export default {
gutterBottom: {
marginBottom: 8
}
};
import MuiButton from './MuiButton';
import MuiIconButton from './MuiIconButton';
import MuiPaper from './MuiPaper';
import MuiTableCell from './MuiTableCell';
import MuiTableHead from './MuiTableHead';
import MuiTypography from './MuiTypography';
export default {
MuiButton,
MuiIconButton,
MuiPaper,
MuiTableCell,
MuiTableHead,
MuiTypography
};
import { colors } from '@material-ui/core';
const white = '#FFFFFF';
const black = '#000000';
export default {
black,
white,
primary: {
contrastText: white,
dark: colors.indigo[900],
main: colors.indigo[500],
light: colors.indigo[100]
},
secondary: {
contrastText: white,
dark: colors.blue[900],
main: colors.blue['A400'],
light: colors.blue['A400']
},
success: {
contrastText: white,
dark: colors.green[900],
main: colors.green[600],
light: colors.green[400]
},
info: {
contrastText: white,
dark: colors.blue[900],
main: colors.blue[600],
light: colors.blue[400]
},
warning: {
contrastText: white,
dark: colors.orange[900],
main: colors.orange[600],
light: colors.orange[400]
},
error: {
contrastText: white,
dark: colors.red[900],
main: colors.red[600],
light: colors.red[400]
},
text: {
primary: colors.blueGrey[900],
secondary: colors.blueGrey[600],
link: colors.blue[600]
},
background: {
default: '#F4F6F8',
paper: white
},
icon: colors.blueGrey[600],
divider: colors.grey[200]
};
import palette from './palette';
export default {
h1: {
color: palette.text.primary,
fontWeight: 500,
fontSize: '35px',
letterSpacing: '-0.24px',
lineHeight: '40px'
},
h2: {
color: palette.text.primary,
fontWeight: 500,
fontSize: '29px',
letterSpacing: '-0.24px',
lineHeight: '32px'
},
h3: {
color: palette.text.primary,
fontWeight: 500,
fontSize: '24px',
letterSpacing: '-0.06px',
lineHeight: '28px'
},
h4: {
color: palette.text.primary,
fontWeight: 500,
fontSize: '20px',
letterSpacing: '-0.06px',
lineHeight: '24px'
},
h5: {
color: palette.text.primary,
fontWeight: 500,
fontSize: '16px',
letterSpacing: '-0.05px',
lineHeight: '20px'
},
h6: {
color: palette.text.primary,
fontWeight: 500,
fontSize: '14px',
letterSpacing: '-0.05px',
lineHeight: '20px'
},
subtitle1: {
color: palette.text.primary,
fontSize: '16px',
letterSpacing: '-0.05px',
lineHeight: '25px'
},
subtitle2: {
color: palette.text.secondary,
fontWeight: 400,
fontSize: '14px',
letterSpacing: '-0.05px',
lineHeight: '21px'
},
body1: {
color: palette.text.primary,
fontSize: '14px',
letterSpacing: '-0.05px',
lineHeight: '21px'
},
body2: {
color: palette.text.secondary,
fontSize: '12px',
letterSpacing: '-0.04px',
lineHeight: '18px'
},
button: {
color: palette.text.primary,
fontSize: '14px'
},
caption: {
color: palette.text.secondary,
fontSize: '11px',
letterSpacing: '0.33px',
lineHeight: '13px'
},
overline: {
color: palette.text.secondary,
fontSize: '11px',
fontWeight: 500,
letterSpacing: '0.33px',
lineHeight: '13px',
textTransform: 'uppercase'
}
};
import React from 'react';
import { makeStyles } from '@material-ui/styles';
import { Grid } from '@material-ui/core';
import { AccountProfile, AccountDetails } from './components';
const useStyles = makeStyles(theme => ({
root: {
padding: theme.spacing(4)
}
}));
const Account = () => {
const classes = useStyles();
return (
<div className={classes.root}>
<Grid
container
spacing={4}
>
<Grid
item
lg={4}
md={6}
xl={4}
xs={12}
>
<AccountProfile />
</Grid>
<Grid
item
lg={8}
md={6}
xl={8}
xs={12}
>
<AccountDetails />
</Grid>
</Grid>
</div>
);
};
export default Account;
import React, { useState } from 'react';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/styles';
import {
Card,
CardHeader,
CardContent,
CardActions,
Divider,
Grid,
Button,
TextField
} from '@material-ui/core';
const useStyles = makeStyles(() => ({
root: {}
}));
const AccountDetails = props => {
const { className, ...rest } = props;
const classes = useStyles();
const [values, setValues] = useState({
firstName: 'Shen',
lastName: 'Zhi',
email: 'shen.zhi@devias.io',
phone: '',
state: 'Alabama',
country: 'USA'
});
const handleChange = event => {
setValues({
...values,
[event.target.name]: event.target.value
});
};
const states = [
{
value: 'alabama',
label: 'Alabama'
},
{
value: 'new-york',
label: 'New York'
},
{
value: 'san-francisco',
label: 'San Francisco'
}
];
return (
<Card
{...rest}
className={clsx(classes.root, className)}
>
<form
autoComplete="off"
noValidate
>
<CardHeader
subheader="The information can be edited"
title="Profile"
/>
<Divider />
<CardContent>
<Grid
container
spacing={3}
>
<Grid
item
md={6}
xs={12}
>
<TextField
fullWidth
helperText="Please specify the first name"
label="First name"
margin="dense"
name="firstName"
onChange={handleChange}
required
value={values.firstName}
variant="outlined"
/>
</Grid>
<Grid
item
md={6}
xs={12}
>
<TextField
fullWidth
label="Last name"
margin="dense"
name="lastName"
onChange={handleChange}
required
value={values.lastName}
variant="outlined"
/>
</Grid>
<Grid
item
md={6}
xs={12}
>
<TextField
fullWidth
label="Email Address"
margin="dense"
name="email"
onChange={handleChange}
required
value={values.email}
variant="outlined"
/>
</Grid>
<Grid
item
md={6}
xs={12}
>
<TextField
fullWidth
label="Phone Number"
margin="dense"
name="phone"
onChange={handleChange}
type="number"
value={values.phone}
variant="outlined"
/>
</Grid>
<Grid
item
md={6}
xs={12}
>
<TextField
fullWidth
label="Select State"
margin="dense"
name="state"
onChange={handleChange}
required
select
// eslint-disable-next-line react/jsx-sort-props
SelectProps={{ native: true }}
value={values.state}
variant="outlined"
>
{states.map(option => (
<option
key={option.value}
value={option.value}
>
{option.label}
</option>
))}
</TextField>
</Grid>
<Grid
item
md={6}
xs={12}
>
<TextField
fullWidth
label="Country"
margin="dense"
name="country"
onChange={handleChange}
required
value={values.country}
variant="outlined"
/>
</Grid>
</Grid>
</CardContent>
<Divider />
<CardActions>
<Button
color="primary"
variant="contained"
>
Save details
</Button>
</CardActions>
</form>
</Card>
);
};
AccountDetails.propTypes = {
className: PropTypes.string
};
export default AccountDetails;
import React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import moment from 'moment';
import { makeStyles } from '@material-ui/styles';
import {
Card,
CardActions,
CardContent,
Avatar,
Typography,
Divider,
Button,
LinearProgress
} from '@material-ui/core';
const useStyles = makeStyles(theme => ({
root: {},
details: {
display: 'flex'
},
avatar: {
marginLeft: 'auto',
height: 110,
width: 100,
flexShrink: 0,
flexGrow: 0
},
progress: {
marginTop: theme.spacing(2)
},
uploadButton: {
marginRight: theme.spacing(2)
}
}));
const AccountProfile = props => {
const { className, ...rest } = props;
const classes = useStyles();
const user = {
name: 'Shen Zhi',
city: 'Los Angeles',
country: 'USA',
timezone: 'GTM-7',
avatar: '/images/avatars/avatar_11.png'
};
return (
<Card
{...rest}
className={clsx(classes.root, className)}
>
<CardContent>
<div className={classes.details}>
<div>
<Typography
gutterBottom
variant="h2"
>
John Doe
</Typography>
<Typography
className={classes.locationText}
color="textSecondary"
variant="body1"
>
{user.city}, {user.country}
</Typography>
<Typography
className={classes.dateText}
color="textSecondary"
variant="body1"
>
{moment().format('hh:mm A')} ({user.timezone})
</Typography>
</div>
<Avatar
className={classes.avatar}
src={user.avatar}
/>
</div>
<div className={classes.progress}>
<Typography variant="body1">Profile Completeness: 70%</Typography>
<LinearProgress
value={70}
variant="determinate"
/>
</div>
</CardContent>
<Divider />
<CardActions>
<Button
className={classes.uploadButton}
color="primary"
variant="text"
>
Upload picture
</Button>
<Button variant="text">Remove picture</Button>
</CardActions>
</Card>
);
};
AccountProfile.propTypes = {
className: PropTypes.string
};
export default AccountProfile;
export { default as AccountDetails } from './AccountDetails';
export { default as AccountProfile } from './AccountProfile';
export { default } from './Account';
import React from 'react';
import { makeStyles } from '@material-ui/styles';
import { Grid } from '@material-ui/core';
import {
Budget,
TotalUsers,
TasksProgress,
TotalProfit,
LatestSales,
UsersByDevice,
LatestProducts,
LatestOrders
} from './components';
const useStyles = makeStyles(theme => ({
root: {
padding: theme.spacing(4)
}
}));
const Dashboard = () => {
const classes = useStyles();
return (
<div className={classes.root}>
<Grid
container
spacing={4}
>
<Grid
item
lg={3}
sm={6}
xl={3}
xs={12}
>
<Budget />
</Grid>
<Grid
item
lg={3}
sm={6}
xl={3}
xs={12}
>
<TotalUsers />
</Grid>
<Grid
item
lg={3}
sm={6}
xl={3}
xs={12}
>
<TasksProgress />
</Grid>
<Grid
item
lg={3}
sm={6}
xl={3}
xs={12}
>
<TotalProfit />
</Grid>
<Grid
item
lg={8}
md={12}
xl={9}
xs={12}
>
<LatestSales />
</Grid>
<Grid
item
lg={4}
md={6}
xl={3}
xs={12}
>
<UsersByDevice />
</Grid>
<Grid
item
lg={4}
md={6}
xl={3}
xs={12}
>
<LatestProducts />
</Grid>
<Grid
item
lg={8}
md={12}
xl={9}
xs={12}
>
<LatestOrders />
</Grid>
</Grid>
</div>
);
};
export default Dashboard;
import React from 'react';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/styles';
import { Card, CardContent, Grid, Typography, Avatar } from '@material-ui/core';
import ArrowDownwardIcon from '@material-ui/icons/ArrowDownward';
import MoneyIcon from '@material-ui/icons/Money';
const useStyles = makeStyles(theme => ({
root: {
height: '100%'
},
content: {
alignItems: 'center',
display: 'flex'
},
title: {
fontWeight: 700
},
avatar: {
backgroundColor: theme.palette.error.main,
height: 56,
width: 56
},
icon: {
height: 32,
width: 32
},
difference: {
marginTop: theme.spacing(2),
display: 'flex',
alignItems: 'center'
},
differenceIcon: {
color: theme.palette.error.dark
},
differenceValue: {
color: theme.palette.error.dark,
marginRight: theme.spacing(1)
}
}));
const Budget = props => {
const { className, ...rest } = props;
const classes = useStyles();
return (
<Card
{...rest}
className={clsx(classes.root, className)}
>
<CardContent>
<Grid
container
justify="space-between"
>
<Grid item>
<Typography
className={classes.title}
color="textSecondary"
gutterBottom
variant="body2"
>
BUDGET
</Typography>
<Typography variant="h3">$24,000</Typography>
</Grid>
<Grid item>
<Avatar className={classes.avatar}>
<MoneyIcon className={classes.icon} />
</Avatar>
</Grid>
</Grid>
<div className={classes.difference}>
<ArrowDownwardIcon className={classes.differenceIcon} />
<Typography
className={classes.differenceValue}
variant="body2"
>
12%
</Typography>
<Typography
className={classes.caption}
variant="caption"
>
Since last month
</Typography>
</div>
</CardContent>
</Card>
);
};
Budget.propTypes = {
className: PropTypes.string
};
export default Budget;
import React, { useState } from 'react';
import clsx from 'clsx';
import moment from 'moment';
import PerfectScrollbar from 'react-perfect-scrollbar';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/styles';
import {
Card,
CardActions,
CardHeader,
CardContent,
Button,
Divider,
Table,
TableBody,
TableCell,
TableHead,
TableRow,
Tooltip,
TableSortLabel
} from '@material-ui/core';
import ArrowRightIcon from '@material-ui/icons/ArrowRight';
import mockData from './data';
import { StatusBullet } from 'components';
const useStyles = makeStyles(theme => ({
root: {},
content: {
padding: 0
},
inner: {
minWidth: 800
},
statusContainer: {
display: 'flex',
alignItems: 'center'
},
status: {
marginRight: theme.spacing(1)
},
actions: {
justifyContent: 'flex-end'
}
}));
const statusColors = {
delivered: 'success',
pending: 'info',
refunded: 'danger'
};
const LatestOrders = props => {
const { className, ...rest } = props;
const classes = useStyles();
const [orders] = useState(mockData);
return (
<Card
{...rest}
className={clsx(classes.root, className)}
>
<CardHeader
action={
<Button
color="primary"
size="small"
variant="outlined"
>
New entry
</Button>
}
title="Latest Orders"
/>
<Divider />
<CardContent className={classes.content}>
<PerfectScrollbar>
<div className={classes.inner}>
<Table>
<TableHead>
<TableRow>
<TableCell>Order Ref</TableCell>
<TableCell>Customer</TableCell>
<TableCell sortDirection="desc">
<Tooltip
enterDelay={300}
title="Sort"
>
<TableSortLabel
active
direction="desc"
>
Date
</TableSortLabel>
</Tooltip>
</TableCell>
<TableCell>Status</TableCell>
</TableRow>
</TableHead>
<TableBody>
{orders.map(order => (
<TableRow
hover
key={order.id}
>
<TableCell>{order.ref}</TableCell>
<TableCell>{order.customer.name}</TableCell>
<TableCell>
{moment(order.createdAt).format('DD/MM/YYYY')}
</TableCell>
<TableCell>
<div className={classes.statusContainer}>
<StatusBullet
className={classes.status}
color={statusColors[order.status]}
size="sm"
/>
{order.status}
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</PerfectScrollbar>
</CardContent>
<Divider />
<CardActions className={classes.actions}>
<Button
color="primary"
size="small"
variant="text"
>
View all <ArrowRightIcon />
</Button>
</CardActions>
</Card>
);
};
LatestOrders.propTypes = {
className: PropTypes.string
};
export default LatestOrders;
import uuid from 'uuid/v1';
export default [
{
id: uuid(),
ref: 'CDD1049',
amount: 30.5,
customer: {
name: 'Ekaterina Tankova'
},
createdAt: 1555016400000,
status: 'pending'
},
{
id: uuid(),
ref: 'CDD1048',
amount: 25.1,
customer: {
name: 'Cao Yu'
},
createdAt: 1555016400000,
status: 'delivered'
},
{
id: uuid(),
ref: 'CDD1047',
amount: 10.99,
customer: {
name: 'Alexa Richardson'
},
createdAt: 1554930000000,
status: 'refunded'
},
{
id: uuid(),
ref: 'CDD1046',
amount: 96.43,
customer: {
name: 'Anje Keizer'
},
createdAt: 1554757200000,
status: 'pending'
},
{
id: uuid(),
ref: 'CDD1045',
amount: 32.54,
customer: {
name: 'Clarke Gillebert'
},
createdAt: 1554670800000,
status: 'delivered'
},
{
id: uuid(),
ref: 'CDD1044',
amount: 16.76,
customer: {
name: 'Adam Denisov'
},
createdAt: 1554670800000,
status: 'delivered'
}
];
import React, { useState } from 'react';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/styles';
import {
Card,
CardHeader,
CardContent,
CardActions,
Button,
Divider,
List,
ListItem,
ListItemAvatar,
ListItemText,
IconButton
} from '@material-ui/core';
import ArrowRightIcon from '@material-ui/icons/ArrowRight';
import MoreVertIcon from '@material-ui/icons/MoreVert';
import mockData from './data';
const useStyles = makeStyles(() => ({
root: {
height: '100%'
},
content: {
padding: 0
},
image: {
height: 48,
width: 48
},
actions: {
justifyContent: 'flex-end'
}
}));
const LatestProducts = props => {
const { className, ...rest } = props;
const classes = useStyles();
const [products] = useState(mockData);
return (
<Card
{...rest}
className={clsx(classes.root, className)}
>
<CardHeader
subtitle={`${products.length} in total`}
title="Latest products"
/>
<Divider />
<CardContent className={classes.content}>
<List>
{products.map((product, i) => (
<ListItem
divider={i < products.length - 1}
key={product.id}
>
<ListItemAvatar>
<img
alt="Product"
className={classes.image}
src={product.imageUrl}
/>
</ListItemAvatar>
<ListItemText
primary={product.name}
secondary={`Updated ${product.updatedAt.fromNow()}`}
/>
<IconButton
edge="end"
size="small"
>
<MoreVertIcon />
</IconButton>
</ListItem>
))}
</List>
</CardContent>
<Divider />
<CardActions className={classes.actions}>
<Button
color="primary"
size="small"
variant="text"
>
View all <ArrowRightIcon />
</Button>
</CardActions>
</Card>
);
};
LatestProducts.propTypes = {
className: PropTypes.string
};
export default LatestProducts;
import uuid from 'uuid/v1';
import moment from 'moment';
export default [
{
id: uuid(),
name: 'Dropbox',
imageUrl: '/images/products/product_1.png',
updatedAt: moment().subtract(2, 'hours')
},
{
id: uuid(),
name: 'Medium Corporation',
imageUrl: '/images/products/product_2.png',
updatedAt: moment().subtract(2, 'hours')
},
{
id: uuid(),
name: 'Slack',
imageUrl: '/images/products/product_3.png',
updatedAt: moment().subtract(3, 'hours')
},
{
id: uuid(),
name: 'Lyft',
imageUrl: '/images/products/product_4.png',
updatedAt: moment().subtract(5, 'hours')
},
{
id: uuid(),
name: 'GitHub',
imageUrl: '/images/products/product_5.png',
updatedAt: moment().subtract(9, 'hours')
}
];
import React from 'react';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import { Bar } from 'react-chartjs-2';
import { makeStyles } from '@material-ui/styles';
import {
Card,
CardHeader,
CardContent,
CardActions,
Divider,
Button
} from '@material-ui/core';
import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';
import ArrowRightIcon from '@material-ui/icons/ArrowRight';
import { data, options } from './chart';
const useStyles = makeStyles(() => ({
root: {},
chartContainer: {
height: 400,
position: 'relative'
},
actions: {
justifyContent: 'flex-end'
}
}));
const LatestSales = props => {
const { className, ...rest } = props;
const classes = useStyles();
return (
<Card
{...rest}
className={clsx(classes.root, className)}
>
<CardHeader
action={
<Button
size="small"
variant="text"
>
Last 7 days <ArrowDropDownIcon />
</Button>
}
title="Latest Sales"
/>
<Divider />
<CardContent>
<div className={classes.chartContainer}>
<Bar
data={data}
options={options}
/>
</div>
</CardContent>
<Divider />
<CardActions className={classes.actions}>
<Button
color="primary"
size="small"
variant="text"
>
Overview <ArrowRightIcon />
</Button>
</CardActions>
</Card>
);
};
LatestSales.propTypes = {
className: PropTypes.string
};
export default LatestSales;
import palette from 'theme/palette';
export const data = {
labels: ['1 Aug', '2 Aug', '3 Aug', '4 Aug', '5 Aug', '6 Aug'],
datasets: [
{
label: 'This year',
backgroundColor: palette.primary.main,
data: [18, 5, 19, 27, 29, 19, 20]
},
{
label: 'Last year',
backgroundColor: palette.neutral,
data: [11, 20, 12, 29, 30, 25, 13]
}
]
};
export const options = {
responsive: true,
maintainAspectRatio: false,
animation: false,
legend: { display: false },
cornerRadius: 20,
tooltips: {
enabled: true,
mode: 'index',
intersect: false,
borderWidth: 1,
borderColor: palette.divider,
backgroundColor: palette.white,
titleFontColor: palette.text.primary,
bodyFontColor: palette.text.secondary,
footerFontColor: palette.text.secondary
},
layout: { padding: 0 },
scales: {
xAxes: [
{
barThickness: 12,
maxBarThickness: 10,
barPercentage: 0.5,
categoryPercentage: 0.5,
ticks: {
fontColor: palette.text.secondary
},
gridLines: {
display: false,
drawBorder: false
}
}
],
yAxes: [
{
ticks: {
fontColor: palette.text.secondary,
beginAtZero: true,
min: 0
},
gridLines: {
borderDash: [2],
borderDashOffset: [2],
color: palette.divider,
drawBorder: false,
zeroLineBorderDash: [2],
zeroLineBorderDashOffset: [2],
zeroLineColor: palette.divider
}
}
]
}
};
import React from 'react';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/styles';
import {
Card,
CardContent,
Grid,
Typography,
Avatar,
LinearProgress
} from '@material-ui/core';
import InsertChartIcon from '@material-ui/icons/InsertChartOutlined';
const useStyles = makeStyles(theme => ({
root: {
height: '100%'
},
content: {
alignItems: 'center',
display: 'flex'
},
title: {
fontWeight: 700
},
avatar: {
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText,
height: 56,
width: 56
},
icon: {
height: 32,
width: 32
},
progress: {
marginTop: theme.spacing(3)
}
}));
const TasksProgress = props => {
const { className, ...rest } = props;
const classes = useStyles();
return (
<Card
{...rest}
className={clsx(classes.root, className)}
>
<CardContent>
<Grid
container
justify="space-between"
>
<Grid item>
<Typography
className={classes.title}
color="textSecondary"
gutterBottom
variant="body2"
>
TASKS PROGRESS
</Typography>
<Typography variant="h3">75.5%</Typography>
</Grid>
<Grid item>
<Avatar className={classes.avatar}>
<InsertChartIcon className={classes.icon} />
</Avatar>
</Grid>
</Grid>
<LinearProgress
className={classes.progress}
value={75.5}
variant="determinate"
/>
</CardContent>
</Card>
);
};
TasksProgress.propTypes = {
className: PropTypes.string
};
export default TasksProgress;
import React from 'react';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/styles';
import { Card, CardContent, Grid, Typography, Avatar } from '@material-ui/core';
import AttachMoneyIcon from '@material-ui/icons/AttachMoney';
const useStyles = makeStyles(theme => ({
root: {
height: '100%',
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText
},
content: {
alignItems: 'center',
display: 'flex'
},
title: {
fontWeight: 700
},
avatar: {
backgroundColor: theme.palette.white,
color: theme.palette.primary.main,
height: 56,
width: 56
},
icon: {
height: 32,
width: 32
}
}));
const TotalProfit = props => {
const { className, ...rest } = props;
const classes = useStyles();
return (
<Card
{...rest}
className={clsx(classes.root, className)}
>
<CardContent>
<Grid
container
justify="space-between"
>
<Grid item>
<Typography
className={classes.title}
color="inherit"
gutterBottom
variant="body2"
>
TOTAL PROFIT
</Typography>
<Typography
color="inherit"
variant="h3"
>
$23,200
</Typography>
</Grid>
<Grid item>
<Avatar className={classes.avatar}>
<AttachMoneyIcon className={classes.icon} />
</Avatar>
</Grid>
</Grid>
</CardContent>
</Card>
);
};
TotalProfit.propTypes = {
className: PropTypes.string
};
export default TotalProfit;
import React from 'react';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/styles';
import { Card, CardContent, Grid, Typography, Avatar } from '@material-ui/core';
import ArrowUpwardIcon from '@material-ui/icons/ArrowUpward';
import PeopleIcon from '@material-ui/icons/PeopleOutlined';
const useStyles = makeStyles(theme => ({
root: {
height: '100%'
},
content: {
alignItems: 'center',
display: 'flex'
},
title: {
fontWeight: 700
},
avatar: {
backgroundColor: theme.palette.success.main,
height: 56,
width: 56
},
icon: {
height: 32,
width: 32
},
difference: {
marginTop: theme.spacing(2),
display: 'flex',
alignItems: 'center'
},
differenceIcon: {
color: theme.palette.success.dark
},
differenceValue: {
color: theme.palette.success.dark,
marginRight: theme.spacing(1)
}
}));
const TotalUsers = props => {
const { className, ...rest } = props;
const classes = useStyles();
return (
<Card
{...rest}
className={clsx(classes.root, className)}
>
<CardContent>
<Grid
container
justify="space-between"
>
<Grid item>
<Typography
className={classes.title}
color="textSecondary"
gutterBottom
variant="body2"
>
TOTAL USERS
</Typography>
<Typography variant="h3">1,600</Typography>
</Grid>
<Grid item>
<Avatar className={classes.avatar}>
<PeopleIcon className={classes.icon} />
</Avatar>
</Grid>
</Grid>
<div className={classes.difference}>
<ArrowUpwardIcon className={classes.differenceIcon} />
<Typography
className={classes.differenceValue}
variant="body2"
>
16%
</Typography>
<Typography
className={classes.caption}
variant="caption"
>
Since last month
</Typography>
</div>
</CardContent>
</Card>
);
};
TotalUsers.propTypes = {
className: PropTypes.string
};
export default TotalUsers;
import React from 'react';
import { Doughnut } from 'react-chartjs-2';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import { makeStyles, useTheme } from '@material-ui/styles';
import {
Card,
CardHeader,
CardContent,
IconButton,
Divider,
Typography
} from '@material-ui/core';
import LaptopMacIcon from '@material-ui/icons/LaptopMac';
import PhoneIphoneIcon from '@material-ui/icons/PhoneIphone';
import RefreshIcon from '@material-ui/icons/Refresh';
import TabletMacIcon from '@material-ui/icons/TabletMac';
const useStyles = makeStyles(theme => ({
root: {
height: '100%'
},
chartContainer: {
position: 'relative',
height: '300px'
},
stats: {
marginTop: theme.spacing(2),
display: 'flex',
justifyContent: 'center'
},
device: {
textAlign: 'center',
padding: theme.spacing(1)
},
deviceIcon: {
color: theme.palette.icon
}
}));
const UsersByDevice = props => {
const { className, ...rest } = props;
const classes = useStyles();
const theme = useTheme();
const data = {
datasets: [
{
data: [63, 15, 22],
backgroundColor: [
theme.palette.primary.main,
theme.palette.error.main,
theme.palette.warning.main
],
borderWidth: 8,
borderColor: theme.palette.white,
hoverBorderColor: theme.palette.white
}
],
labels: ['Desktop', 'Tablet', 'Mobile']
};
const options = {
legend: {
display: false
},
responsive: true,
maintainAspectRatio: false,
animation: false,
cutoutPercentage: 80,
layout: { padding: 0 },
tooltips: {
enabled: true,
mode: 'index',
intersect: false,
borderWidth: 1,
borderColor: theme.palette.divider,
backgroundColor: theme.palette.white,
titleFontColor: theme.palette.text.primary,
bodyFontColor: theme.palette.text.secondary,
footerFontColor: theme.palette.text.secondary
}
};
const devices = [
{
title: 'Desktop',
value: '63',
icon: <LaptopMacIcon />,
color: theme.palette.primary.main
},
{
title: 'Tablet',
value: '15',
icon: <TabletMacIcon />,
color: theme.palette.error.main
},
{
title: 'Mobile',
value: '23',
icon: <PhoneIphoneIcon />,
color: theme.palette.warning.main
}
];
return (
<Card
{...rest}
className={clsx(classes.root, className)}
>
<CardHeader
action={
<IconButton size="small">
<RefreshIcon />
</IconButton>
}
title="Users By Device"
/>
<Divider />
<CardContent>
<div className={classes.chartContainer}>
<Doughnut
data={data}
options={options}
/>
</div>
<div className={classes.stats}>
{devices.map(device => (
<div
className={classes.device}
key={device.title}
>
<span className={classes.deviceIcon}>{device.icon}</span>
<Typography variant="body1">{device.title}</Typography>
<Typography
style={{ color: device.color }}
variant="h2"
>
{device.value}%
</Typography>
</div>
))}
</div>
</CardContent>
</Card>
);
};
UsersByDevice.propTypes = {
className: PropTypes.string
};
export default UsersByDevice;
export { default as Budget } from './Budget';
export { default as LatestOrders } from './LatestOrders';
export { default as LatestProducts } from './LatestProducts';
export { default as LatestSales } from './LatestSales';
export { default as TasksProgress } from './TasksProgress';
export { default as TotalProfit } from './TotalProfit';
export { default as TotalUsers } from './TotalUsers';
export { default as UsersByDevice } from './UsersByDevice';
export { default } from './Dashboard';
import React from 'react';
import { makeStyles } from '@material-ui/styles';
const useStyles = makeStyles(theme => ({
root: {
padding: theme.spacing(4)
},
iframe: {
width: '100%',
minHeight: 640,
border: 0
}
}));
const Icons = () => {
const classes = useStyles();
return (
<div className={classes.root}>
<iframe
className={classes.iframe}
src="https://material.io/tools/icons/?icon=accessibility&style=outline"
title="Material Design icons"
/>
</div>
);
};
export default Icons;
export { default } from './Icons';
import React from 'react';
import { makeStyles } from '@material-ui/styles';
import { Grid, Typography } from '@material-ui/core';
const useStyles = makeStyles(theme => ({
root: {
padding: theme.spacing(4)
},
content: {
paddingTop: 150,
textAlign: 'center'
},
image: {
marginTop: 50,
display: 'inline-block',
maxWidth: '100%',
width: 560
}
}));
const NotFound = () => {
const classes = useStyles();
return (
<div className={classes.root}>
<Grid
container
justify="center"
spacing={4}
>
<Grid
item
lg={6}
xs={12}
>
<div className={classes.content}>
<Typography variant="h1">
404: The page you are looking for isnt here
</Typography>
<Typography variant="subtitle2">
You either tried some shady route or you came here by mistake.
Whichever it is, try using the navigation
</Typography>
<img
alt="Under development"
className={classes.image}
src="/images/undraw_page_not_found_su7k.svg"
/>
</div>
</Grid>
</Grid>
</div>
);
};
export default NotFound;
export { default } from './NotFound';
import React, { useState } from 'react';
import { makeStyles } from '@material-ui/styles';
import { IconButton, Grid, Typography } from '@material-ui/core';
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
import ChevronLeftIcon from '@material-ui/icons/ChevronLeft';
import { ProductsToolbar, ProductCard } from './components';
import mockData from './data';
const useStyles = makeStyles(theme => ({
root: {
padding: theme.spacing(3)
},
content: {
marginTop: theme.spacing(2)
},
pagination: {
marginTop: theme.spacing(3),
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end'
}
}));
const ProductList = () => {
const classes = useStyles();
const [products] = useState(mockData);
return (
<div className={classes.root}>
<ProductsToolbar />
<div className={classes.content}>
<Grid
container
spacing={3}
>
{products.map(product => (
<Grid
item
key={product.id}
lg={4}
md={6}
xs={12}
>
<ProductCard product={product} />
</Grid>
))}
</Grid>
</div>
<div className={classes.pagination}>
<Typography variant="caption">1-6 of 20</Typography>
<IconButton>
<ChevronLeftIcon />
</IconButton>
<IconButton>
<ChevronRightIcon />
</IconButton>
</div>
</div>
);
};
export default ProductList;
import React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { makeStyles } from '@material-ui/styles';
import {
Card,
CardContent,
CardActions,
Typography,
Grid,
Divider
} from '@material-ui/core';
import AccessTimeIcon from '@material-ui/icons/AccessTime';
import GetAppIcon from '@material-ui/icons/GetApp';
const useStyles = makeStyles(theme => ({
root: {},
imageContainer: {
height: 64,
width: 64,
margin: '0 auto',
border: `1px solid ${theme.palette.divider}`,
borderRadius: '5px',
overflow: 'hidden',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
},
image: {
width: '100%'
},
statsItem: {
display: 'flex',
alignItems: 'center'
},
statsIcon: {
color: theme.palette.icon,
marginRight: theme.spacing(1)
}
}));
const ProductCard = props => {
const { className, product, ...rest } = props;
const classes = useStyles();
return (
<Card
{...rest}
className={clsx(classes.root, className)}
>
<CardContent>
<div className={classes.imageContainer}>
<img
alt="Product"
className={classes.image}
src={product.imageUrl}
/>
</div>
<Typography
align="center"
gutterBottom
variant="h4"
>
{product.title}
</Typography>
<Typography
align="center"
variant="body1"
>
{product.description}
</Typography>
</CardContent>
<Divider />
<CardActions>
<Grid
container
justify="space-between"
>
<Grid
className={classes.statsItem}
item
>
<AccessTimeIcon className={classes.statsIcon} />
<Typography
display="inline"
variant="body2"
>
Updated 2hr ago
</Typography>
</Grid>
<Grid
className={classes.statsItem}
item
>
<GetAppIcon className={classes.statsIcon} />
<Typography
display="inline"
variant="body2"
>
{product.totalDownloads} Downloads
</Typography>
</Grid>
</Grid>
</CardActions>
</Card>
);
};
ProductCard.propTypes = {
className: PropTypes.string,
product: PropTypes.object.isRequired
};
export default ProductCard;
import React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { makeStyles } from '@material-ui/styles';
import { Button } from '@material-ui/core';
import { SearchInput } from 'components';
const useStyles = makeStyles(theme => ({
root: {},
row: {
height: '42px',
display: 'flex',
alignItems: 'center',
marginTop: theme.spacing(1)
},
spacer: {
flexGrow: 1
},
importButton: {
marginRight: theme.spacing(1)
},
exportButton: {
marginRight: theme.spacing(1)
},
searchInput: {
marginRight: theme.spacing(1)
}
}));
const ProductsToolbar = props => {
const { className, ...rest } = props;
const classes = useStyles();
return (
<div
{...rest}
className={clsx(classes.root, className)}
>
<div className={classes.row}>
<span className={classes.spacer} />
<Button className={classes.importButton}>Import</Button>
<Button className={classes.exportButton}>Export</Button>
<Button
color="primary"
variant="contained"
>
Add product
</Button>
</div>
<div className={classes.row}>
<SearchInput
className={classes.searchInput}
placeholder="Search product"
/>
</div>
</div>
);
};
ProductsToolbar.propTypes = {
className: PropTypes.string
};
export default ProductsToolbar;
export { default as ProductCard } from './ProductCard';
export { default as ProductsToolbar } from './ProductsToolbar';
import uuid from 'uuid/v1';
export default [
{
id: uuid(),
title: 'Dropbox',
description:
'Dropbox is a file hosting service that offers cloud storage, file synchronization, a personal cloud.',
imageUrl: '/images/products/product_1.png',
totalDownloads: '594',
updatedAt: '27/03/2019'
},
{
id: uuid(),
title: 'Medium Corporation',
description:
'Medium is an online publishing platform developed by Evan Williams, and launched in August 2012.',
imageUrl: '/images/products/product_2.png',
totalDownloads: '625',
createdAt: '31/03/2019'
},
{
id: uuid(),
title: 'Slack',
description:
'Slack is a cloud-based set of team collaboration tools and services, founded by Stewart Butterfield.',
imageUrl: '/images/products/product_3.png',
totalDownloads: '857',
createdAt: '03/04/2019'
},
{
id: uuid(),
title: 'Lyft',
description:
'Lyft is an on-demand transportation company based in San Francisco, California.',
imageUrl: '/images/products/product_4.png',
totalDownloads: '406',
createdAt: '04/04/2019'
},
{
id: uuid(),
title: 'GitHub',
description:
'GitHub is a web-based hosting service for version control of code using Git.',
imageUrl: '/images/products/product_5.png',
totalDownloads: '835',
createdAt: '04/04/2019'
},
{
id: uuid(),
title: 'Squarespace',
description:
'Squarespace provides software as a service for website building and hosting. Headquartered in NYC.',
imageUrl: '/images/products/product_6.png',
totalDownloads: '835',
createdAt: '04/04/2019'
}
];
export { default } from './ProductList';
import React from 'react';
import { makeStyles } from '@material-ui/styles';
import { Grid } from '@material-ui/core';
import { Notifications, Password } from './components';
const useStyles = makeStyles(theme => ({
root: {
padding: theme.spacing(4)
}
}));
const Settings = () => {
const classes = useStyles();
return (
<div className={classes.root}>
<Grid
container
spacing={4}
>
<Grid
item
md={7}
xs={12}
>
<Notifications />
</Grid>
<Grid
item
md={5}
xs={12}
>
<Password />
</Grid>
</Grid>
</div>
);
};
export default Settings;
import React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { makeStyles } from '@material-ui/styles';
import {
Card,
CardHeader,
CardContent,
CardActions,
Grid,
Divider,
FormControlLabel,
Checkbox,
Typography,
Button
} from '@material-ui/core';
const useStyles = makeStyles(() => ({
root: {},
item: {
display: 'flex',
flexDirection: 'column'
}
}));
const Notifications = props => {
const { className, ...rest } = props;
const classes = useStyles();
return (
<Card
{...rest}
className={clsx(classes.root, className)}
>
<form>
<CardHeader
subheader="Manage the notifications"
title="Notifications"
/>
<Divider />
<CardContent>
<Grid
container
spacing={6}
wrap="wrap"
>
<Grid
className={classes.item}
item
md={4}
sm={6}
xs={12}
>
<Typography
gutterBottom
variant="h6"
>
Notifications
</Typography>
<FormControlLabel
control={
<Checkbox
color="primary"
defaultChecked //
/>
}
label="Email"
/>
<FormControlLabel
control={
<Checkbox
color="primary"
defaultChecked //
/>
}
label="Push Notifications"
/>
<FormControlLabel
control={<Checkbox color="primary" />}
label="Text Messages"
/>
<FormControlLabel
control={
<Checkbox
color="primary"
defaultChecked //
/>
}
label="Phone calls"
/>
</Grid>
<Grid
className={classes.item}
item
md={4}
sm={6}
xs={12}
>
<Typography
gutterBottom
variant="h6"
>
Messages
</Typography>
<FormControlLabel
control={
<Checkbox
color="primary"
defaultChecked //
/>
}
label="Email"
/>
<FormControlLabel
control={<Checkbox color="primary" />}
label="Push Notifications"
/>
<FormControlLabel
control={
<Checkbox
color="primary"
defaultChecked //
/>
}
label="Phone calls"
/>
</Grid>
</Grid>
</CardContent>
<Divider />
<CardActions>
<Button
color="primary"
variant="outlined"
>
Save
</Button>
</CardActions>
</form>
</Card>
);
};
Notifications.propTypes = {
className: PropTypes.string
};
export default Notifications;
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { makeStyles } from '@material-ui/styles';
import {
Card,
CardHeader,
CardContent,
CardActions,
Divider,
Button,
TextField
} from '@material-ui/core';
const useStyles = makeStyles(() => ({
root: {}
}));
const Password = props => {
const { className, ...rest } = props;
const classes = useStyles();
const [values, setValues] = useState({
password: '',
confirm: ''
});
const handleChange = event => {
setValues({
...values,
[event.target.name]: event.target.value
});
};
return (
<Card
{...rest}
className={clsx(classes.root, className)}
>
<form>
<CardHeader
subheader="Update password"
title="Password"
/>
<Divider />
<CardContent>
<TextField
fullWidth
label="Password"
name="password"
onChange={handleChange}
type="password"
value={values.password}
variant="outlined"
/>
<TextField
fullWidth
label="Confirm password"
name="confirm"
onChange={handleChange}
style={{ marginTop: '1rem' }}
type="password"
value={values.confirm}
variant="outlined"
/>
</CardContent>
<Divider />
<CardActions>
<Button
color="primary"
variant="outlined"
>
Update
</Button>
</CardActions>
</form>
</Card>
);
};
Password.propTypes = {
className: PropTypes.string
};
export default Password;
export { default as Notifications } from './Notifications';
export { default as Password } from './Password';
export { default } from './Settings';
import React, { useState, useEffect } from 'react';
import { Link as RouterLink, withRouter } from 'react-router-dom';
import PropTypes from 'prop-types';
import validate from 'validate.js';
import { makeStyles } from '@material-ui/styles';
import {
Grid,
Button,
IconButton,
TextField,
Link,
Typography
} from '@material-ui/core';
import ArrowBackIcon from '@material-ui/icons/ArrowBack';
import { Facebook as FacebookIcon, Google as GoogleIcon } from 'icons';
const schema = {
email: {
presence: { allowEmpty: false, message: 'is required' },
email: true,
length: {
maximum: 64
}
},
password: {
presence: { allowEmpty: false, message: 'is required' },
length: {
maximum: 128
}
}
};
const useStyles = makeStyles(theme => ({
root: {
backgroundColor: theme.palette.background.default,
height: '100%'
},
grid: {
height: '100%'
},
quoteContainer: {
[theme.breakpoints.down('md')]: {
display: 'none'
}
},
quote: {
backgroundColor: theme.palette.neutral,
height: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
backgroundImage: 'url(/images/auth.jpg)',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center'
},
quoteInner: {
textAlign: 'center',
flexBasis: '600px'
},
quoteText: {
color: theme.palette.white,
fontWeight: 300
},
name: {
marginTop: theme.spacing(3),
color: theme.palette.white
},
bio: {
color: theme.palette.white
},
contentContainer: {},
content: {
height: '100%',
display: 'flex',
flexDirection: 'column'
},
contentHeader: {
display: 'flex',
alignItems: 'center',
paddingTop: theme.spacing(5),
paddingBototm: theme.spacing(2),
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(2)
},
logoImage: {
marginLeft: theme.spacing(4)
},
contentBody: {
flexGrow: 1,
display: 'flex',
alignItems: 'center',
[theme.breakpoints.down('md')]: {
justifyContent: 'center'
}
},
form: {
paddingLeft: 100,
paddingRight: 100,
paddingBottom: 125,
flexBasis: 700,
[theme.breakpoints.down('sm')]: {
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(2)
}
},
title: {
marginTop: theme.spacing(3)
},
socialButtons: {
marginTop: theme.spacing(3)
},
socialIcon: {
marginRight: theme.spacing(1)
},
sugestion: {
marginTop: theme.spacing(2)
},
textField: {
marginTop: theme.spacing(2)
},
signInButton: {
margin: theme.spacing(2, 0)
}
}));
const SignIn = props => {
const { history } = props;
const classes = useStyles();
const [formState, setFormState] = useState({
isValid: false,
values: {},
touched: {},
errors: {}
});
useEffect(() => {
const errors = validate(formState.values, schema);
setFormState(formState => ({
...formState,
isValid: errors ? false : true,
errors: errors || {}
}));
}, [formState.values]);
const handleBack = () => {
history.goBack();
};
const handleChange = event => {
event.persist();
setFormState(formState => ({
...formState,
values: {
...formState.values,
[event.target.name]:
event.target.type === 'checkbox'
? event.target.checked
: event.target.value
},
touched: {
...formState.touched,
[event.target.name]: true
}
}));
};
const handleSignIn = event => {
event.preventDefault();
history.push('/');
};
const hasError = field =>
formState.touched[field] && formState.errors[field] ? true : false;
return (
<div className={classes.root}>
<Grid
className={classes.grid}
container
>
<Grid
className={classes.quoteContainer}
item
lg={5}
>
<div className={classes.quote}>
<div className={classes.quoteInner}>
<Typography
className={classes.quoteText}
variant="h1"
>
Hella narwhal Cosby sweater McSweeney's, salvia kitsch before
they sold out High Life.
</Typography>
<div className={classes.person}>
<Typography
className={classes.name}
variant="body1"
>
Takamaru Ayako
</Typography>
<Typography
className={classes.bio}
variant="body2"
>
Manager at inVision
</Typography>
</div>
</div>
</div>
</Grid>
<Grid
className={classes.content}
item
lg={7}
xs={12}
>
<div className={classes.content}>
<div className={classes.contentHeader}>
<IconButton onClick={handleBack}>
<ArrowBackIcon />
</IconButton>
</div>
<div className={classes.contentBody}>
<form
className={classes.form}
onSubmit={handleSignIn}
>
<Typography
className={classes.title}
variant="h2"
>
Sign in
</Typography>
<Typography
color="textSecondary"
gutterBottom
>
Sign in with social media
</Typography>
<Grid
className={classes.socialButtons}
container
spacing={2}
>
<Grid item>
<Button
color="primary"
onClick={handleSignIn}
size="large"
variant="contained"
>
<FacebookIcon className={classes.socialIcon} />
Login with Facebook
</Button>
</Grid>
<Grid item>
<Button
onClick={handleSignIn}
size="large"
variant="contained"
>
<GoogleIcon className={classes.socialIcon} />
Login with Google
</Button>
</Grid>
</Grid>
<Typography
align="center"
className={classes.sugestion}
color="textSecondary"
variant="body1"
>
or login with email address
</Typography>
<TextField
className={classes.textField}
error={hasError('email')}
fullWidth
helperText={
hasError('email') ? formState.errors.email[0] : null
}
label="Email address"
name="email"
onChange={handleChange}
type="text"
value={formState.values.email || ''}
variant="outlined"
/>
<TextField
className={classes.textField}
error={hasError('password')}
fullWidth
helperText={
hasError('password') ? formState.errors.password[0] : null
}
label="Password"
name="password"
onChange={handleChange}
type="password"
value={formState.values.password || ''}
variant="outlined"
/>
<Button
className={classes.signInButton}
color="primary"
disabled={!formState.isValid}
fullWidth
size="large"
type="submit"
variant="contained"
>
Sign in now
</Button>
<Typography
color="textSecondary"
variant="body1"
>
Don't have an account?{' '}
<Link
component={RouterLink}
to="/sign-up"
variant="h6"
>
Sign up
</Link>
</Typography>
</form>
</div>
</div>
</Grid>
</Grid>
</div>
);
};
SignIn.propTypes = {
history: PropTypes.object
};
export default withRouter(SignIn);
export { default } from './SignIn';
import React, { useState, useEffect } from 'react';
import { Link as RouterLink, withRouter } from 'react-router-dom';
import PropTypes from 'prop-types';
import validate from 'validate.js';
import { makeStyles } from '@material-ui/styles';
import {
Grid,
Button,
IconButton,
TextField,
Link,
FormHelperText,
Checkbox,
Typography
} from '@material-ui/core';
import ArrowBackIcon from '@material-ui/icons/ArrowBack';
const schema = {
firstName: {
presence: { allowEmpty: false, message: 'is required' },
length: {
maximum: 32
}
},
lastName: {
presence: { allowEmpty: false, message: 'is required' },
length: {
maximum: 32
}
},
email: {
presence: { allowEmpty: false, message: 'is required' },
email: true,
length: {
maximum: 64
}
},
password: {
presence: { allowEmpty: false, message: 'is required' },
length: {
maximum: 128
}
},
policy: {
presence: { allowEmpty: false, message: 'is required' },
checked: true
}
};
const useStyles = makeStyles(theme => ({
root: {
backgroundColor: theme.palette.background.default,
height: '100%'
},
grid: {
height: '100%'
},
quoteContainer: {
[theme.breakpoints.down('md')]: {
display: 'none'
}
},
quote: {
backgroundColor: theme.palette.neutral,
height: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
backgroundImage: 'url(/images/auth.jpg)',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center'
},
quoteInner: {
textAlign: 'center',
flexBasis: '600px'
},
quoteText: {
color: theme.palette.white,
fontWeight: 300
},
name: {
marginTop: theme.spacing(3),
color: theme.palette.white
},
bio: {
color: theme.palette.white
},
contentContainer: {},
content: {
height: '100%',
display: 'flex',
flexDirection: 'column'
},
contentHeader: {
display: 'flex',
alignItems: 'center',
paddingTop: theme.spacing(5),
paddingBototm: theme.spacing(2),
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(2)
},
logoImage: {
marginLeft: theme.spacing(4)
},
contentBody: {
flexGrow: 1,
display: 'flex',
alignItems: 'center',
[theme.breakpoints.down('md')]: {
justifyContent: 'center'
}
},
form: {
paddingLeft: 100,
paddingRight: 100,
paddingBottom: 125,
flexBasis: 700,
[theme.breakpoints.down('sm')]: {
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(2)
}
},
title: {
marginTop: theme.spacing(3)
},
textField: {
marginTop: theme.spacing(2)
},
policy: {
marginTop: theme.spacing(1),
display: 'flex',
alignItems: 'center'
},
policyCheckbox: {
marginLeft: '-14px'
},
signUpButton: {
margin: theme.spacing(2, 0)
}
}));
const SignUp = props => {
const { history } = props;
const classes = useStyles();
const [formState, setFormState] = useState({
isValid: false,
values: {},
touched: {},
errors: {}
});
useEffect(() => {
const errors = validate(formState.values, schema);
setFormState(formState => ({
...formState,
isValid: errors ? false : true,
errors: errors || {}
}));
}, [formState.values]);
const handleChange = event => {
event.persist();
setFormState(formState => ({
...formState,
values: {
...formState.values,
[event.target.name]:
event.target.type === 'checkbox'
? event.target.checked
: event.target.value
},
touched: {
...formState.touched,
[event.target.name]: true
}
}));
};
const handleBack = () => {
history.goBack();
};
const handleSignUp = event => {
event.preventDefault();
history.push('/');
};
const hasError = field =>
formState.touched[field] && formState.errors[field] ? true : false;
return (
<div className={classes.root}>
<Grid
className={classes.grid}
container
>
<Grid
className={classes.quoteContainer}
item
lg={5}
>
<div className={classes.quote}>
<div className={classes.quoteInner}>
<Typography
className={classes.quoteText}
variant="h1"
>
Hella narwhal Cosby sweater McSweeney's, salvia kitsch before
they sold out High Life.
</Typography>
<div className={classes.person}>
<Typography
className={classes.name}
variant="body1"
>
Takamaru Ayako
</Typography>
<Typography
className={classes.bio}
variant="body2"
>
Manager at inVision
</Typography>
</div>
</div>
</div>
</Grid>
<Grid
className={classes.content}
item
lg={7}
xs={12}
>
<div className={classes.content}>
<div className={classes.contentHeader}>
<IconButton onClick={handleBack}>
<ArrowBackIcon />
</IconButton>
</div>
<div className={classes.contentBody}>
<form
className={classes.form}
onSubmit={handleSignUp}
>
<Typography
className={classes.title}
variant="h2"
>
Create new account
</Typography>
<Typography
color="textSecondary"
gutterBottom
>
Use your email to create new account
</Typography>
<TextField
className={classes.textField}
error={hasError('firstName')}
fullWidth
helperText={
hasError('firstName') ? formState.errors.firstName[0] : null
}
label="First name"
name="firstName"
onChange={handleChange}
type="text"
value={formState.values.firstName || ''}
variant="outlined"
/>
<TextField
className={classes.textField}
error={hasError('lastName')}
fullWidth
helperText={
hasError('lastName') ? formState.errors.lastName[0] : null
}
label="Last name"
name="lastName"
onChange={handleChange}
type="text"
value={formState.values.lastName || ''}
variant="outlined"
/>
<TextField
className={classes.textField}
error={hasError('email')}
fullWidth
helperText={
hasError('email') ? formState.errors.email[0] : null
}
label="Email address"
name="email"
onChange={handleChange}
type="text"
value={formState.values.email || ''}
variant="outlined"
/>
<TextField
className={classes.textField}
error={hasError('password')}
fullWidth
helperText={
hasError('password') ? formState.errors.password[0] : null
}
label="Password"
name="password"
onChange={handleChange}
type="password"
value={formState.values.password || ''}
variant="outlined"
/>
<div className={classes.policy}>
<Checkbox
checked={formState.values.policy || false}
className={classes.policyCheckbox}
color="primary"
name="policy"
onChange={handleChange}
/>
<Typography
className={classes.policyText}
color="textSecondary"
variant="body1"
>
I have read the{' '}
<Link
color="primary"
component={RouterLink}
to="#"
underline="always"
variant="h6"
>
Terms and Conditions
</Link>
</Typography>
</div>
{hasError('policy') && (
<FormHelperText error>
{formState.errors.policy[0]}
</FormHelperText>
)}
<Button
className={classes.signUpButton}
color="primary"
disabled={!formState.isValid}
fullWidth
size="large"
type="submit"
variant="contained"
>
Sign up now
</Button>
<Typography
color="textSecondary"
variant="body1"
>
Have an account?{' '}
<Link
component={RouterLink}
to="/sign-in"
variant="h6"
>
Sign in
</Link>
</Typography>
</form>
</div>
</div>
</Grid>
</Grid>
</div>
);
};
SignUp.propTypes = {
history: PropTypes.object
};
export default withRouter(SignUp);
export { default } from './SignUp';
import React, { Fragment } from 'react';
import { makeStyles } from '@material-ui/styles';
import { Grid, Typography as MuiTypography } from '@material-ui/core';
const useStyles = makeStyles(theme => ({
root: {
padding: theme.spacing(4)
}
}));
const variants = {
h1: 'Nisi euismod ante senectus consequat phasellus ut',
h2: 'Nisi euismod ante senectus consequat phasellus ut',
h3: 'Nisi euismod ante senectus consequat phasellus ut',
h4: 'Nisi euismod ante senectus consequat phasellus ut',
h5: 'Nisi euismod ante senectus consequat phasellus ut',
h6: 'Nisi euismod ante senectus consequat phasellus ut',
subtitle1: 'Leo varius justo aptent arcu urna felis pede nisl',
subtitle2: 'Leo varius justo aptent arcu urna felis pede nisl',
body1:
'Justo proin curabitur dictumst semper auctor, consequat tempor, nostra aenean neque turpis nunc. Leo. Sapien aliquet facilisi turpis, elit facilisi praesent porta metus leo. Dignissim amet dis nec ac integer inceptos erat dis Turpis sodales ad torquent. Dolor, erat convallis.Laoreet velit a fames commodo tristique hendrerit sociosqu rhoncus vel sapien penatibus facilisis faucibus ad. Mus purus vehicula imperdiet tempor lectus, feugiat Sapien erat viverra netus potenti mattis purus turpis. Interdum curabitur potenti tristique. Porta velit dignissim tristique ultrices primis.',
body2:
'Justo proin curabitur dictumst semper auctor, consequat tempor, nostra aenean neque turpis nunc. Leo. Sapien aliquet facilisi turpis, elit facilisi praesent porta metus leo. Dignissim amet dis nec ac integer inceptos erat dis Turpis sodales ad torquent. Dolor, erat convallis.',
caption: 'Accumsan leo pretium conubia ullamcorper.',
overline: 'Accumsan leo pretium conubia ullamcorper.',
button: 'Vivamus ultrices rutrum fames dictumst'
};
const Typography = () => {
const classes = useStyles();
return (
<div className={classes.root}>
<Grid
container
spacing={4}
>
{Object.keys(variants).map((key, i) => (
<Fragment key={i}>
<Grid
item
sm={3}
xs={12}
>
<MuiTypography variant="caption">{key}</MuiTypography>
</Grid>
<Grid
item
sm={9}
xs={12}
>
<MuiTypography variant={key}>{variants[key]}</MuiTypography>
</Grid>
</Fragment>
))}
</Grid>
</div>
);
};
export default Typography;
export { default } from './Typography';
import React, { useState } from 'react';
import { makeStyles } from '@material-ui/styles';
import { UsersToolbar, UsersTable } from './components';
import mockData from './data';
const useStyles = makeStyles(theme => ({
root: {
padding: theme.spacing(3)
},
content: {
marginTop: theme.spacing(2)
}
}));
const UserList = () => {
const classes = useStyles();
const [users] = useState(mockData);
return (
<div className={classes.root}>
<UsersToolbar />
<div className={classes.content}>
<UsersTable users={users} />
</div>
</div>
);
};
export default UserList;
import React, { useState } from 'react';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import moment from 'moment';
import PerfectScrollbar from 'react-perfect-scrollbar';
import { makeStyles } from '@material-ui/styles';
import {
Card,
CardActions,
CardContent,
Avatar,
Checkbox,
Table,
TableBody,
TableCell,
TableHead,
TableRow,
Typography,
TablePagination
} from '@material-ui/core';
import { getInitials } from 'helpers';
const useStyles = makeStyles(theme => ({
root: {},
content: {
padding: 0
},
inner: {
minWidth: 1050
},
nameContainer: {
display: 'flex',
alignItems: 'center'
},
avatar: {
marginRight: theme.spacing(2)
},
actions: {
justifyContent: 'flex-end'
}
}));
const UsersTable = props => {
const { className, users, ...rest } = props;
const classes = useStyles();
const [selectedUsers, setSelectedUsers] = useState([]);
const [rowsPerPage, setRowsPerPage] = useState(10);
const [page, setPage] = useState(0);
const handleSelectAll = event => {
const { users } = props;
let selectedUsers;
if (event.target.checked) {
selectedUsers = users.map(user => user.id);
} else {
selectedUsers = [];
}
setSelectedUsers(selectedUsers);
};
const handleSelectOne = (event, id) => {
const selectedIndex = selectedUsers.indexOf(id);
let newSelectedUsers = [];
if (selectedIndex === -1) {
newSelectedUsers = newSelectedUsers.concat(selectedUsers, id);
} else if (selectedIndex === 0) {
newSelectedUsers = newSelectedUsers.concat(selectedUsers.slice(1));
} else if (selectedIndex === selectedUsers.length - 1) {
newSelectedUsers = newSelectedUsers.concat(selectedUsers.slice(0, -1));
} else if (selectedIndex > 0) {
newSelectedUsers = newSelectedUsers.concat(
selectedUsers.slice(0, selectedIndex),
selectedUsers.slice(selectedIndex + 1)
);
}
setSelectedUsers(newSelectedUsers);
};
const handlePageChange = (event, page) => {
setPage(page);
};
const handleRowsPerPageChange = event => {
setRowsPerPage(event.target.value);
};
return (
<Card
{...rest}
className={clsx(classes.root, className)}
>
<CardContent className={classes.content}>
<PerfectScrollbar>
<div className={classes.inner}>
<Table>
<TableHead>
<TableRow>
<TableCell padding="checkbox">
<Checkbox
checked={selectedUsers.length === users.length}
color="primary"
indeterminate={
selectedUsers.length > 0 &&
selectedUsers.length < users.length
}
onChange={handleSelectAll}
/>
</TableCell>
<TableCell>Name</TableCell>
<TableCell>Email</TableCell>
<TableCell>Location</TableCell>
<TableCell>Phone</TableCell>
<TableCell>Registration date</TableCell>
</TableRow>
</TableHead>
<TableBody>
{users.slice(0, rowsPerPage).map(user => (
<TableRow
className={classes.tableRow}
hover
key={user.id}
selected={selectedUsers.indexOf(user.id) !== -1}
>
<TableCell padding="checkbox">
<Checkbox
checked={selectedUsers.indexOf(user.id) !== -1}
color="primary"
onChange={event => handleSelectOne(event, user.id)}
value="true"
/>
</TableCell>
<TableCell>
<div className={classes.nameContainer}>
<Avatar
className={classes.avatar}
src={user.avatarUrl}
>
{getInitials(user.name)}
</Avatar>
<Typography variant="body1">{user.name}</Typography>
</div>
</TableCell>
<TableCell>{user.email}</TableCell>
<TableCell>
{user.address.city}, {user.address.state},{' '}
{user.address.country}
</TableCell>
<TableCell>{user.phone}</TableCell>
<TableCell>
{moment(user.createdAt).format('DD/MM/YYYY')}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</PerfectScrollbar>
</CardContent>
<CardActions className={classes.actions}>
<TablePagination
component="div"
count={users.length}
onChangePage={handlePageChange}
onChangeRowsPerPage={handleRowsPerPageChange}
page={page}
rowsPerPage={rowsPerPage}
rowsPerPageOptions={[5, 10, 25]}
/>
</CardActions>
</Card>
);
};
UsersTable.propTypes = {
className: PropTypes.string,
users: PropTypes.array.isRequired
};
export default UsersTable;
import React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { makeStyles } from '@material-ui/styles';
import { Button } from '@material-ui/core';
import { SearchInput } from 'components';
const useStyles = makeStyles(theme => ({
root: {},
row: {
height: '42px',
display: 'flex',
alignItems: 'center',
marginTop: theme.spacing(1)
},
spacer: {
flexGrow: 1
},
importButton: {
marginRight: theme.spacing(1)
},
exportButton: {
marginRight: theme.spacing(1)
},
searchInput: {
marginRight: theme.spacing(1)
}
}));
const UsersToolbar = props => {
const { className, ...rest } = props;
const classes = useStyles();
return (
<div
{...rest}
className={clsx(classes.root, className)}
>
<div className={classes.row}>
<span className={classes.spacer} />
<Button className={classes.importButton}>Import</Button>
<Button className={classes.exportButton}>Export</Button>
<Button
color="primary"
variant="contained"
>
Add user
</Button>
</div>
<div className={classes.row}>
<SearchInput
className={classes.searchInput}
placeholder="Search user"
/>
</div>
</div>
);
};
UsersToolbar.propTypes = {
className: PropTypes.string
};
export default UsersToolbar;
export { default as UsersTable } from './UsersTable';
export { default as UsersToolbar } from './UsersToolbar';
import uuid from 'uuid/v1';
export default [
{
id: uuid(),
name: 'Ekaterina Tankova',
address: {
country: 'USA',
state: 'West Virginia',
city: 'Parkersburg',
street: '2849 Fulton Street'
},
email: 'ekaterina.tankova@devias.io',
phone: '304-428-3097',
avatarUrl: '/images/avatars/avatar_3.png',
createdAt: 1555016400000
},
{
id: uuid(),
name: 'Cao Yu',
address: {
country: 'USA',
state: 'Bristow',
city: 'Iowa',
street: '1865 Pleasant Hill Road'
},
email: 'cao.yu@devias.io',
avatarUrl: '/images/avatars/avatar_4.png',
phone: '712-351-5711',
createdAt: 1555016400000
},
{
id: uuid(),
name: 'Alexa Richardson',
address: {
country: 'USA',
state: 'Georgia',
city: 'Atlanta',
street: '4894 Lakeland Park Drive'
},
email: 'alexa.richardson@devias.io',
phone: '770-635-2682',
avatarUrl: '/images/avatars/avatar_2.png',
createdAt: 1555016400000
},
{
id: uuid(),
name: 'Anje Keizer',
address: {
country: 'USA',
state: 'Ohio',
city: 'Dover',
street: '4158 Hedge Street'
},
email: 'anje.keizer@devias.io',
avatarUrl: '/images/avatars/avatar_5.png',
phone: '908-691-3242',
createdAt: 1554930000000
},
{
id: uuid(),
name: 'Clarke Gillebert',
address: {
country: 'USA',
state: 'Texas',
city: 'Dallas',
street: '75247'
},
email: 'clarke.gillebert@devias.io',
phone: '972-333-4106',
avatarUrl: '/images/avatars/avatar_6.png',
createdAt: 1554757200000
},
{
id: uuid(),
name: 'Adam Denisov',
address: {
country: 'USA',
state: 'California',
city: 'Bakerfield',
street: '317 Angus Road'
},
email: 'adam.denisov@devias.io',
phone: '858-602-3409',
avatarUrl: '/images/avatars/avatar_1.png',
createdAt: 1554670800000
},
{
id: uuid(),
name: 'Ava Gregoraci',
address: {
country: 'USA',
state: 'California',
city: 'Redondo Beach',
street: '2188 Armbrester Drive'
},
email: 'ava.gregoraci@devias.io',
avatarUrl: '/images/avatars/avatar_7.png',
phone: '415-907-2647',
createdAt: 1554325200000
},
{
id: uuid(),
name: 'Emilee Simchenko',
address: {
country: 'USA',
state: 'Nevada',
city: 'Las Vegas',
street: '1798 Hickory Ridge Drive'
},
email: 'emilee.simchenko@devias.io',
phone: '702-661-1654',
avatarUrl: '/images/avatars/avatar_8.png',
createdAt: 1523048400000
},
{
id: uuid(),
name: 'Kwak Seong-Min',
address: {
country: 'USA',
state: 'Michigan',
city: 'Detroit',
street: '3934 Wildrose Lane'
},
email: 'kwak.seong.min@devias.io',
avatarUrl: '/images/avatars/avatar_9.png',
phone: '313-812-8947'
},
{
id: uuid(),
name: 'Merrile Burgett',
address: {
country: 'USA',
state: 'Utah',
city: 'Salt Lake City',
street: '368 Lamberts Branch Road'
},
email: 'merrile.burgett@devias.io',
phone: '801-301-7894',
avatarUrl: '/images/avatars/avatar_10.png',
createdAt: 1522702800000
}
];
export { default } from './UserList';
export { default as Account } from './Account';
export { default as Dashboard } from './Dashboard';
export { default as Icons } from './Icons';
export { default as NotFound } from './NotFound';
export { default as ProductList } from './ProductList';
export { default as Settings } from './Settings';
export { default as SignIn } from './SignIn';
export { default as SignUp } from './SignUp';
export { default as Typography } from './Typography';
export { default as UserList } from './UserList';