Pavle Golubovic преди 3 години
родител
ревизия
1278fdfadc
променени са 47 файла, в които са добавени 1828 реда и са изтрити 918 реда
  1. 288
    28
      frontend/package-lock.json
  2. 8
    1
      frontend/package.json
  3. 8
    10
      frontend/public/index.html
  4. 18
    0
      frontend/src/App.css
  5. 38
    22
      frontend/src/App.js
  6. Двоични данни
      frontend/src/assets/Cookie.png
  7. Двоични данни
      frontend/src/assets/nick.jpg
  8. 0
    106
      frontend/src/components/CardCareers.jsx
  9. 9
    11
      frontend/src/components/CareerCardsTemplates/CardCareers2.jsx
  10. 1
    1
      frontend/src/components/CareerCardsTemplates/CareerCard.jsx
  11. 210
    0
      frontend/src/components/CareerCardsTemplates/ExpandedCard.jsx
  12. 0
    108
      frontend/src/components/ExpandedCard.jsx
  13. 22
    0
      frontend/src/components/Testimonials.jsx
  14. 1
    1
      frontend/src/components/root/CustomLink.jsx
  15. 56
    88
      frontend/src/components/shared/ClientForm.jsx
  16. 29
    6
      frontend/src/components/shared/Contact.jsx
  17. 46
    0
      frontend/src/components/shared/CookieBanner.jsx
  18. 15
    0
      frontend/src/components/shared/GradientWrapper.jsx
  19. 1
    1
      frontend/src/components/shared/HashPositions.jsx
  20. 86
    11
      frontend/src/components/shared/JobForm.jsx
  21. 4
    5
      frontend/src/components/shared/MyDropzone.jsx
  22. 1
    1
      frontend/src/components/shared/PageTitle.jsx
  23. 21
    0
      frontend/src/components/shared/PageTitleOneFont.jsx
  24. 33
    0
      frontend/src/components/shared/ReactHelmet.jsx
  25. 2
    1
      frontend/src/context/index.js
  26. 10
    13
      frontend/src/hooks/useAnalytics.js
  27. 17
    0
      frontend/src/hooks/useDataApi.js
  28. 8
    6
      frontend/src/index.js
  29. 35
    3
      frontend/src/pages/About.jsx
  30. 83
    34
      frontend/src/pages/Careers.jsx
  31. 141
    140
      frontend/src/pages/CaseStudy.jsx
  32. 13
    5
      frontend/src/pages/CaseStudyBI.jsx
  33. 24
    26
      frontend/src/pages/CaseStudyCentralized.jsx
  34. 12
    6
      frontend/src/pages/CaseStudyFinantial.jsx
  35. 4
    8
      frontend/src/pages/CaseStudyResource.jsx
  36. 5
    8
      frontend/src/pages/CaseStudyStrata.jsx
  37. 6
    11
      frontend/src/pages/CaseStudyTicketing.jsx
  38. 8
    4
      frontend/src/pages/ContactPage.jsx
  39. 22
    3
      frontend/src/pages/Home.jsx
  40. 34
    3
      frontend/src/pages/Portfolio.jsx
  41. 7
    10
      frontend/src/pages/ProcessPage.jsx
  42. 257
    199
      frontend/src/pages/WorkWithUs.jsx
  43. 2
    2
      frontend/src/styles/buttons.css
  44. 17
    1
      frontend/src/styles/text.css
  45. 13
    0
      frontend/src/utils/strapiApiBuilder.js
  46. 95
    25
      frontend/tailwind.config.js
  47. 118
    10
      frontend/yarn.lock

+ 288
- 28
frontend/package-lock.json Целия файл

{ {
"name": "frontend", "name": "frontend",
"version": "1.0.20",
"version": "1.1.18",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "frontend", "name": "frontend",
"version": "1.0.20",
"version": "1.1.18",
"dependencies": { "dependencies": {
"@faceless-ui/slider": "^1.1.14", "@faceless-ui/slider": "^1.1.14",
"@faceless-ui/window-info": "^2.1.1", "@faceless-ui/window-info": "^2.1.1",
"emailjs": "^4.0.0", "emailjs": "^4.0.0",
"emailjs-com": "^3.2.0", "emailjs-com": "^3.2.0",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.0.0",
"form-data": "^4.0.0",
"formik": "^2.2.9", "formik": "^2.2.9",
"framer-motion": "^6.3.4", "framer-motion": "^6.3.4",
"mailgun.js": "^8.0.6",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"react": "^17.0.2", "react": "^17.0.2",
"react-cookie": "^4.1.1",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-dropzone": "^12.0.5", "react-dropzone": "^12.0.5",
"react-ga": "^3.3.1",
"react-ga4": "^1.4.1",
"react-google-recaptcha": "^2.1.0",
"react-helmet-async": "^1.3.0",
"react-mailchimp-subscribe": "^2.1.3", "react-mailchimp-subscribe": "^2.1.3",
"react-markdown": "^8.0.0", "react-markdown": "^8.0.0",
"react-router-dom": "^6.2.1", "react-router-dom": "^6.2.1",
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/cookie": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz",
"integrity": "sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow=="
},
"node_modules/@types/debug": { "node_modules/@types/debug": {
"version": "4.1.7", "version": "4.1.7",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz",
"@types/unist": "*" "@types/unist": "*"
} }
}, },
"node_modules/@types/hoist-non-react-statics": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
"integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
"dependencies": {
"@types/react": "*",
"hoist-non-react-statics": "^3.3.0"
}
},
"node_modules/@types/html-minifier-terser": { "node_modules/@types/html-minifier-terser": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz",
"node_modules/@types/prop-types": { "node_modules/@types/prop-types": {
"version": "15.7.5", "version": "15.7.5",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
"integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==",
"peer": true
"integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
}, },
"node_modules/@types/q": { "node_modules/@types/q": {
"version": "1.5.5", "version": "1.5.5",
"version": "18.0.21", "version": "18.0.21",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.21.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.21.tgz",
"integrity": "sha512-7QUCOxvFgnD5Jk8ZKlUAhVcRj7GuJRjnjjiY/IUBWKgOlnvDvTMLD4RTF7NPyVmbRhNrbomZiOepg7M/2Kj1mA==", "integrity": "sha512-7QUCOxvFgnD5Jk8ZKlUAhVcRj7GuJRjnjjiY/IUBWKgOlnvDvTMLD4RTF7NPyVmbRhNrbomZiOepg7M/2Kj1mA==",
"peer": true,
"dependencies": { "dependencies": {
"@types/prop-types": "*", "@types/prop-types": "*",
"@types/scheduler": "*", "@types/scheduler": "*",
"node_modules/@types/scheduler": { "node_modules/@types/scheduler": {
"version": "0.16.2", "version": "0.16.2",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==",
"peer": true
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
}, },
"node_modules/@types/serve-index": { "node_modules/@types/serve-index": {
"version": "1.9.1", "version": "1.9.1",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
}, },
"node_modules/base-64": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz",
"integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg=="
},
"node_modules/batch": { "node_modules/batch": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
"node_modules/csstype": { "node_modules/csstype": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
"integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==",
"peer": true
"integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="
}, },
"node_modules/damerau-levenshtein": { "node_modules/damerau-levenshtein": {
"version": "1.0.8", "version": "1.0.8",
"integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==" "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw=="
}, },
"node_modules/follow-redirects": { "node_modules/follow-redirects": {
"version": "1.14.8",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
} }
}, },
"node_modules/form-data": { "node_modules/form-data": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": { "dependencies": {
"asynckit": "^0.4.0", "asynckit": "^0.4.0",
"combined-stream": "^1.0.8", "combined-stream": "^1.0.8",
} }
} }
}, },
"node_modules/jsdom/node_modules/form-data": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/jsesc": { "node_modules/jsesc": {
"version": "2.5.2", "version": "2.5.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
"sourcemap-codec": "^1.4.4" "sourcemap-codec": "^1.4.4"
} }
}, },
"node_modules/mailgun.js": {
"version": "8.0.6",
"resolved": "https://registry.npmjs.org/mailgun.js/-/mailgun.js-8.0.6.tgz",
"integrity": "sha512-b+c7QO1T4oFsudEcRB2H7oZKth8ZDeYRW4xjW12QQVNYDSJCVxqSQfps6ofcH8fqcCMJdzc76HVNGdnUZgBPCw==",
"dependencies": {
"axios": "^0.27.2",
"base-64": "^1.0.0",
"url-join": "^4.0.1"
}
},
"node_modules/mailgun.js/node_modules/axios": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
"dependencies": {
"follow-redirects": "^1.14.9",
"form-data": "^4.0.0"
}
},
"node_modules/make-dir": { "node_modules/make-dir": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
"node": ">=14" "node": ">=14"
} }
}, },
"node_modules/react-async-script": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz",
"integrity": "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==",
"dependencies": {
"hoist-non-react-statics": "^3.3.0",
"prop-types": "^15.5.0"
},
"peerDependencies": {
"react": ">=16.4.1"
}
},
"node_modules/react-cookie": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/react-cookie/-/react-cookie-4.1.1.tgz",
"integrity": "sha512-ffn7Y7G4bXiFbnE+dKhHhbP+b8I34mH9jqnm8Llhj89zF4nPxPutxHT1suUqMeCEhLDBI7InYwf1tpaSoK5w8A==",
"dependencies": {
"@types/hoist-non-react-statics": "^3.0.1",
"hoist-non-react-statics": "^3.0.0",
"universal-cookie": "^4.0.0"
},
"peerDependencies": {
"react": ">= 16.3.0"
}
},
"node_modules/react-dev-utils": { "node_modules/react-dev-utils": {
"version": "12.0.0", "version": "12.0.0",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.0.tgz", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.0.tgz",
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
"integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
}, },
"node_modules/react-ga": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/react-ga/-/react-ga-3.3.1.tgz",
"integrity": "sha512-4Vc0W5EvXAXUN/wWyxvsAKDLLgtJ3oLmhYYssx+YzphJpejtOst6cbIHCIyF50Fdxuf5DDKqRYny24yJ2y7GFQ==",
"peerDependencies": {
"prop-types": "^15.6.0",
"react": "^15.6.2 || ^16.0 || ^17 || ^18"
}
},
"node_modules/react-ga4": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/react-ga4/-/react-ga4-1.4.1.tgz",
"integrity": "sha512-ioBMEIxd4ePw4YtaloTUgqhQGqz5ebDdC4slEpLgy2sLx1LuZBC9iYCwDymTXzcntw6K1dHX183ulP32nNdG7w=="
},
"node_modules/react-google-recaptcha": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-2.1.0.tgz",
"integrity": "sha512-K9jr7e0CWFigi8KxC3WPvNqZZ47df2RrMAta6KmRoE4RUi7Ys6NmNjytpXpg4HI/svmQJLKR+PncEPaNJ98DqQ==",
"dependencies": {
"prop-types": "^15.5.0",
"react-async-script": "^1.1.1"
},
"peerDependencies": {
"react": ">=16.4.1"
}
},
"node_modules/react-helmet-async": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.3.0.tgz",
"integrity": "sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==",
"dependencies": {
"@babel/runtime": "^7.12.5",
"invariant": "^2.2.4",
"prop-types": "^15.7.2",
"react-fast-compare": "^3.2.0",
"shallowequal": "^1.1.0"
},
"peerDependencies": {
"react": "^16.6.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-helmet-async/node_modules/react-fast-compare": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz",
"integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA=="
},
"node_modules/react-is": { "node_modules/react-is": {
"version": "16.13.1", "version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"url": "https://opencollective.com/unified" "url": "https://opencollective.com/unified"
} }
}, },
"node_modules/universal-cookie": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-4.0.4.tgz",
"integrity": "sha512-lbRVHoOMtItjWbM7TwDLdl8wug7izB0tq3/YVKhT/ahB4VDvWMyvnADfnJI8y6fSvsjh51Ix7lTGC6Tn4rMPhw==",
"dependencies": {
"@types/cookie": "^0.3.3",
"cookie": "^0.4.0"
}
},
"node_modules/universalify": { "node_modules/universalify": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
"punycode": "^2.1.0" "punycode": "^2.1.0"
} }
}, },
"node_modules/url-join": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
"integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="
},
"node_modules/util-deprecate": { "node_modules/util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"@types/node": "*" "@types/node": "*"
} }
}, },
"@types/cookie": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz",
"integrity": "sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow=="
},
"@types/debug": { "@types/debug": {
"version": "4.1.7", "version": "4.1.7",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz",
"@types/unist": "*" "@types/unist": "*"
} }
}, },
"@types/hoist-non-react-statics": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
"integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
"requires": {
"@types/react": "*",
"hoist-non-react-statics": "^3.3.0"
}
},
"@types/html-minifier-terser": { "@types/html-minifier-terser": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz",
"@types/prop-types": { "@types/prop-types": {
"version": "15.7.5", "version": "15.7.5",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
"integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==",
"peer": true
"integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
}, },
"@types/q": { "@types/q": {
"version": "1.5.5", "version": "1.5.5",
"version": "18.0.21", "version": "18.0.21",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.21.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.21.tgz",
"integrity": "sha512-7QUCOxvFgnD5Jk8ZKlUAhVcRj7GuJRjnjjiY/IUBWKgOlnvDvTMLD4RTF7NPyVmbRhNrbomZiOepg7M/2Kj1mA==", "integrity": "sha512-7QUCOxvFgnD5Jk8ZKlUAhVcRj7GuJRjnjjiY/IUBWKgOlnvDvTMLD4RTF7NPyVmbRhNrbomZiOepg7M/2Kj1mA==",
"peer": true,
"requires": { "requires": {
"@types/prop-types": "*", "@types/prop-types": "*",
"@types/scheduler": "*", "@types/scheduler": "*",
"@types/scheduler": { "@types/scheduler": {
"version": "0.16.2", "version": "0.16.2",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==",
"peer": true
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
}, },
"@types/serve-index": { "@types/serve-index": {
"version": "1.9.1", "version": "1.9.1",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
}, },
"base-64": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz",
"integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg=="
},
"batch": { "batch": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
"csstype": { "csstype": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
"integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==",
"peer": true
"integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="
}, },
"damerau-levenshtein": { "damerau-levenshtein": {
"version": "1.0.8", "version": "1.0.8",
"integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==" "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw=="
}, },
"follow-redirects": { "follow-redirects": {
"version": "1.14.8",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA=="
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
}, },
"fork-ts-checker-webpack-plugin": { "fork-ts-checker-webpack-plugin": {
"version": "6.5.0", "version": "6.5.0",
} }
}, },
"form-data": { "form-data": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"requires": { "requires": {
"asynckit": "^0.4.0", "asynckit": "^0.4.0",
"combined-stream": "^1.0.8", "combined-stream": "^1.0.8",
"whatwg-url": "^8.5.0", "whatwg-url": "^8.5.0",
"ws": "^7.4.6", "ws": "^7.4.6",
"xml-name-validator": "^3.0.0" "xml-name-validator": "^3.0.0"
},
"dependencies": {
"form-data": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
}
} }
}, },
"jsesc": { "jsesc": {
"sourcemap-codec": "^1.4.4" "sourcemap-codec": "^1.4.4"
} }
}, },
"mailgun.js": {
"version": "8.0.6",
"resolved": "https://registry.npmjs.org/mailgun.js/-/mailgun.js-8.0.6.tgz",
"integrity": "sha512-b+c7QO1T4oFsudEcRB2H7oZKth8ZDeYRW4xjW12QQVNYDSJCVxqSQfps6ofcH8fqcCMJdzc76HVNGdnUZgBPCw==",
"requires": {
"axios": "^0.27.2",
"base-64": "^1.0.0",
"url-join": "^4.0.1"
},
"dependencies": {
"axios": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
"requires": {
"follow-redirects": "^1.14.9",
"form-data": "^4.0.0"
}
}
}
},
"make-dir": { "make-dir": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
"whatwg-fetch": "^3.6.2" "whatwg-fetch": "^3.6.2"
} }
}, },
"react-async-script": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz",
"integrity": "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==",
"requires": {
"hoist-non-react-statics": "^3.3.0",
"prop-types": "^15.5.0"
}
},
"react-cookie": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/react-cookie/-/react-cookie-4.1.1.tgz",
"integrity": "sha512-ffn7Y7G4bXiFbnE+dKhHhbP+b8I34mH9jqnm8Llhj89zF4nPxPutxHT1suUqMeCEhLDBI7InYwf1tpaSoK5w8A==",
"requires": {
"@types/hoist-non-react-statics": "^3.0.1",
"hoist-non-react-statics": "^3.0.0",
"universal-cookie": "^4.0.0"
}
},
"react-dev-utils": { "react-dev-utils": {
"version": "12.0.0", "version": "12.0.0",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.0.tgz", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.0.tgz",
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
"integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
}, },
"react-ga": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/react-ga/-/react-ga-3.3.1.tgz",
"integrity": "sha512-4Vc0W5EvXAXUN/wWyxvsAKDLLgtJ3oLmhYYssx+YzphJpejtOst6cbIHCIyF50Fdxuf5DDKqRYny24yJ2y7GFQ==",
"requires": {}
},
"react-ga4": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/react-ga4/-/react-ga4-1.4.1.tgz",
"integrity": "sha512-ioBMEIxd4ePw4YtaloTUgqhQGqz5ebDdC4slEpLgy2sLx1LuZBC9iYCwDymTXzcntw6K1dHX183ulP32nNdG7w=="
},
"react-google-recaptcha": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-2.1.0.tgz",
"integrity": "sha512-K9jr7e0CWFigi8KxC3WPvNqZZ47df2RrMAta6KmRoE4RUi7Ys6NmNjytpXpg4HI/svmQJLKR+PncEPaNJ98DqQ==",
"requires": {
"prop-types": "^15.5.0",
"react-async-script": "^1.1.1"
}
},
"react-helmet-async": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.3.0.tgz",
"integrity": "sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==",
"requires": {
"@babel/runtime": "^7.12.5",
"invariant": "^2.2.4",
"prop-types": "^15.7.2",
"react-fast-compare": "^3.2.0",
"shallowequal": "^1.1.0"
},
"dependencies": {
"react-fast-compare": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz",
"integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA=="
}
}
},
"react-is": { "react-is": {
"version": "16.13.1", "version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"unist-util-is": "^5.0.0" "unist-util-is": "^5.0.0"
} }
}, },
"universal-cookie": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-4.0.4.tgz",
"integrity": "sha512-lbRVHoOMtItjWbM7TwDLdl8wug7izB0tq3/YVKhT/ahB4VDvWMyvnADfnJI8y6fSvsjh51Ix7lTGC6Tn4rMPhw==",
"requires": {
"@types/cookie": "^0.3.3",
"cookie": "^0.4.0"
}
},
"universalify": { "universalify": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
"punycode": "^2.1.0" "punycode": "^2.1.0"
} }
}, },
"url-join": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
"integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="
},
"util-deprecate": { "util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",

+ 8
- 1
frontend/package.json Целия файл

{ {
"name": "frontend", "name": "frontend",
"version": "1.1.1",
"version": "1.1.18",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@faceless-ui/slider": "^1.1.14", "@faceless-ui/slider": "^1.1.14",
"emailjs": "^4.0.0", "emailjs": "^4.0.0",
"emailjs-com": "^3.2.0", "emailjs-com": "^3.2.0",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.0.0",
"form-data": "^4.0.0",
"formik": "^2.2.9", "formik": "^2.2.9",
"framer-motion": "^6.3.4", "framer-motion": "^6.3.4",
"mailgun.js": "^8.0.6",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"react": "^17.0.2", "react": "^17.0.2",
"react-cookie": "^4.1.1",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-dropzone": "^12.0.5", "react-dropzone": "^12.0.5",
"react-ga": "^3.3.1",
"react-ga4": "^1.4.1",
"react-google-recaptcha": "^2.1.0",
"react-helmet-async": "^1.3.0",
"react-mailchimp-subscribe": "^2.1.3", "react-mailchimp-subscribe": "^2.1.3",
"react-markdown": "^8.0.0", "react-markdown": "^8.0.0",
"react-router-dom": "^6.2.1", "react-router-dom": "^6.2.1",

+ 8
- 10
frontend/public/index.html Целия файл

<link rel="icon" href="%PUBLIC_URL%/favicon_diligent.png" /> <link rel="icon" href="%PUBLIC_URL%/favicon_diligent.png" />
<meta name="viewport" content="width=device-width, height=device-height" /> <meta name="viewport" content="width=device-width, height=device-height" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta
name="description"
content="Diligent Software's Website"
/>
<meta name="description" content="Diligent Software's Website" data-rh="true" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!-- <!--
manifest.json provides metadata used when your web app is installed on a manifest.json provides metadata used when your web app is installed on a
<title>Diligent Software</title> <title>Diligent Software</title>


<!-- Google tag (gtag.js) --> <!-- Google tag (gtag.js) -->
<!-- <script async src='https://www.googletagmanager.com/gtag/js?id=G-PTZC3WLTZ1'></script>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-PD7YZVDG30"></script>
<script> <script>
window.dataLayer = window.dataLayer || []; window.dataLayer = window.dataLayer || [];
function gtag() { dataLayer.push(arguments); }
gtag('js', new Date());
gtag('config', 'G-PTZC3WLTZ1');
</script> -->
function gtag() {
dataLayer.push(arguments);
}
gtag("js", new Date());


gtag("config", "G-PD7YZVDG30");
</script>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>

+ 18
- 0
frontend/src/App.css Целия файл

scrollbar-width: none; /* Firefox */ scrollbar-width: none; /* Firefox */
} }


.radial-gradient {
background: radial-gradient(circle, #ffffff00, #8468BF 60%);
}
.scale-image {
-webkit-transform: scale(1);
transform: scale(1);
-webkit-transform-origin: center;
transform-origin: center;
}
@media only screen and (max-width: 650px) {
.scale-image {
-webkit-transform: scale(1.5);
transform: scale(1.5);
-webkit-transform-origin: center;
transform-origin: center;
}
}

@media only screen and (max-width: 500px) { @media only screen and (max-width: 500px) {
.size-07 { .size-07 {
transform: scale(0.7); transform: scale(0.7);

+ 38
- 22
frontend/src/App.js Целия файл

import './App.css'; import './App.css';
import { Route, Routes, useLocation, useNavigate } from 'react-router-dom'; import { Route, Routes, useLocation, useNavigate } from 'react-router-dom';
import Navigation from './components/shared/Navigation'; import Navigation from './components/shared/Navigation';
import CookieBanner from './components/shared/CookieBanner';
import Footer from './components/shared/Footer'; import Footer from './components/shared/Footer';
import Loader from './components/shared/Loader'; import Loader from './components/shared/Loader';
import ScrollToTop from './components/root/ScrollToTop'; import ScrollToTop from './components/root/ScrollToTop';

import ReactGA from 'react-ga4';
import { useCookies, Cookies } from 'react-cookie';
import routes from './routes'; import routes from './routes';



const Home = lazy(() => import('./pages/Home')); const Home = lazy(() => import('./pages/Home'));
const Portfolio = lazy(() => import('./pages/Portfolio')); const Portfolio = lazy(() => import('./pages/Portfolio'));
const Services = lazy(() => import('./pages/Services')); const Services = lazy(() => import('./pages/Services'));
// Navigation Links // Navigation Links
const links = routes.filter(item => item.nav === true); const links = routes.filter(item => item.nav === true);




function App() { function App() {
//tabs for contact form //tabs for contact form
const link = useNavigate(); const link = useNavigate();

const [cookies, setCookie, removeCookie] = useCookies(['user']);
const [diligentCookie, setDiligentCookie] = useState(cookies.diligent_ga);
//scroll to Contact segment //scroll to Contact segment
const forwardedRef = useRef(null); const forwardedRef = useRef(null);


//initialize analytics page tracking
//usePageTracking();
useEffect(() => {
if (diligentCookie === 'true') {
ReactGA.initialize(process.env.REACT_APP_MEASUREMENT_ID);
}
}, [diligentCookie]);


//scroll to Contact fn //scroll to Contact fn
function scrollToView(event) { function scrollToView(event) {
event.preventDefault(); event.preventDefault();
if (forwardedRef) { if (forwardedRef) {
//console.log(forwardedRef.current.offsetTop); //console.log(forwardedRef.current.offsetTop);
window.scrollTo({ behavior: 'smooth', top: forwardedRef.current.offsetTop })
window.scrollTo({ behavior: 'smooth', top: forwardedRef.current.offsetTop });
} else { } else {
link('/contact'); link('/contact');
} }
} }
} }


const handleAccept = () => {
setCookie('diligent_ga', 'true', { path: '/' });
setDiligentCookie(prevValue => !prevValue);
};

const handleDecline = () => {
setCookie('diligent_ga', 'false', { path: '/' });
setDiligentCookie(prevValue => !prevValue);
};

return ( return (
<div> <div>
<ScrollToTop /> <ScrollToTop />
activeLinks={activeLinks} activeLinks={activeLinks}
forwardedRef={forwardedRef} forwardedRef={forwardedRef}
></Navigation> ></Navigation>
{diligentCookie === undefined && (
<CookieBanner handleAccept={handleAccept} handleDecline={handleDecline} />
)}
<Suspense fallback={<Loader />}> <Suspense fallback={<Loader />}>
<Routes> <Routes>
<Route exact path="/" element={<Home forwardedRef={forwardedRef} />}/>
<Route exact path="/workwithus" element={<WorkWithUs />}/>
<Route exact path="/portfolio" element={<Portfolio />}/>
<Route exact path="/process" element={<ProcessPage />}/>
<Route exact path="/careers" element={<Careers />}/>
<Route exact path="/about" element={<About />}/>
<Route exact path="/contact" element={<ContactPage />}/>
<Route exact path="/casestudybi" element={<CaseStudyBI />}/>
<Route exact path="/casestudystrata" element={<CaseStudyStrata />}/>
<Route exact path="/casestudyfinancial" element={<CaseStudyFinantial />}/>
<Route exact path="/casestudycentralized" element={<CaseStudyCentralized />}/>
<Route exact path="/casestudyresource" element={<CaseStudyResource />}/>
<Route exact path="/casestudyticketing" element={<CaseStudyTicketing />}/>
<Route exact path="/privacypolicy" element={<PrivacyPolicy />}/>
<Route exact path="/" element={<Home forwardedRef={forwardedRef} />} />
<Route exact path="/workwithus" element={<WorkWithUs />} />
<Route exact path="/portfolio" element={<Portfolio />} />
<Route exact path="/process" element={<ProcessPage />} />
<Route exact path="/careers" element={<Careers />} />
<Route exact path="/about" element={<About />} />
<Route exact path="/contact" element={<ContactPage />} />
<Route exact path="/casestudybi" element={<CaseStudyBI />} />
<Route exact path="/casestudystrata" element={<CaseStudyStrata />} />
<Route exact path="/casestudyfinancial" element={<CaseStudyFinantial />} />
<Route exact path="/casestudycentralized" element={<CaseStudyCentralized />} />
<Route exact path="/casestudyresource" element={<CaseStudyResource />} />
<Route exact path="/casestudyticketing" element={<CaseStudyTicketing />} />
<Route exact path="/privacypolicy" element={<PrivacyPolicy />} />
</Routes> </Routes>
</Suspense> </Suspense>



Двоични данни
frontend/src/assets/Cookie.png Целия файл


Двоични данни
frontend/src/assets/nick.jpg Целия файл


+ 0
- 106
frontend/src/components/CardCareers.jsx Целия файл

import propTypes from 'prop-types';

import { useState } from 'react';
import { ReactComponent as BackTriangle } from '../assets/graphics/BackTriangle.svg';
import TriangleButton from './shared/TriangleButton';

const api_url = process.env.REACT_APP_API_URL;



export default function CardCareers(props) {
const [hideJob, setHideJob] = useState(true);

return (

<div
className={'transition-all hover:transition-all pb-0 hover:pb-12 flex flex-col justify-center items-center w-4/5 lg:w-5/6 mb-8 lg:mb-0 lg:mr-8 group'
}
>
{/* Collapsed Card */}
{ hideJob && <div>
<img
src={api_url + props.image}
className={
'ml-auto mr-auto block w-2/5 bg-baby-blue text-dark-gray rounded-full p-4'
}
/>
<h3 className={'mt-6 font-semibold text-2xl'}>
{props.heading}
</h3>
<p className={'mt-6 text-sm'}>{props.paragraph}</p>
<a
href={'#' + props.heading.split(' ')[0]}
onClick={() => setHideJob(!hideJob)}
className={'min-w-max btn btn_primary mt-8 opacity-0 transition-all group-hover:opacity-100 group-hover:transition-all'
}
>
Read More
</a>
</div>}

{/* Expanded Job */}
{ !hideJob && <div
id={props.heading.split(' ')[0]}
className={
!hideJob
? 'hidden'
: 'dark:text-white w-full h-fit shadow-md rounded-md px-12 lg:px-16 py-12 lg:py-16'
}
>
<div className="flex flex-col items-start justify-center text-left">
<div className="flex flex-row items-center justify-start">
<div className='mr-4'>
<TriangleButton onClick={() => setHideJob(!hideJob)} direction={'left'}/>
</div>

<img
src={api_url + props.image}
className="ml-auto mr-auto block w-2/5 bg-baby-blue text-dark-gray rounded-full p-4"
/>
<h3 className="ml-6 w-full font-semibold text-2xl">{props.heading}</h3>
</div>
<p className="mt-6 text-sm">{props.paragraph}</p>
<h4 className="mt-6 font-semibold text-lg">{props.requirements_heading}</h4>
<p className="mt-6 text-sm">{props.requirements_paragraph}</p>
<br />
<h4 className="mt-6 font-semibold text-lg">{props.expectations_heading}</h4>
<p className="mt-6 text-sm">{props.expectations_paragraph}</p>
<h4 className="mt-6 font-semibold text-lg">{props.benefits_heading}</h4>
<p className="mt-6 text-sm">{props.benefits_paragraph}</p>
<div className="flex flex-row w-full items-center justify-end">
<a
href="#contact"
onClick={() => {
setHideJob(!hideJob);
props.setClickedPosition('#' + props.hash_position);
}}
className="btn btn_primary mt-8 transition-all hover:transition-all"
>
Apply
</a>
</div>
</div>
</div>}

</div>
);
}

CardCareers.propTypes = {
key: propTypes.number,
image: propTypes.string,
heading: propTypes.string,
paragraph: propTypes.string,
requirements_heading: propTypes.string,
requirements_paragraph: propTypes.string,
expectations_heading: propTypes.string,
expectations_paragraph: propTypes.string,
benefits_heading: propTypes.string,
benefits_paragraph: propTypes.string,
hash_position: propTypes.string,
setClickedPosition: propTypes.func,
};

frontend/src/components/CardCareers2.jsx → frontend/src/components/CareerCardsTemplates/CardCareers2.jsx Целия файл

import propTypes from 'prop-types'; import propTypes from 'prop-types';


import { useEffect, useState } from 'react';
import { ReactComponent as BackTriangle } from '../assets/graphics/BackTriangle.svg';
import Wrapper from '../layout/Wrapper';
import { useState } from 'react';
import Wrapper from '../../layout/Wrapper';
import ExpandedCard from './ExpandedCard'; import ExpandedCard from './ExpandedCard';
import TriangleButton from './shared/TriangleButton';
import CareerCard from './CareerCard'; import CareerCard from './CareerCard';
import Grid from '../layout/Grid';
import { ref } from 'yup';
import useClickOutside from '../hooks/useClickOutside';
import useComponentVisible from '../hooks/useClickOutside';
//import useClickOutside from '../../hooks/useClickOutside';
import useComponentVisible from '../../hooks/useClickOutside';


const api_url = process.env.REACT_APP_API_URL; const api_url = process.env.REACT_APP_API_URL;


{isComponentVisible ? {isComponentVisible ?
<ExpandedCard card={expandedCard} setExpanded={setIsComponentVisible} setExpandedCard={setExpandedCard}></ExpandedCard> <ExpandedCard card={expandedCard} setExpanded={setIsComponentVisible} setExpandedCard={setExpandedCard}></ExpandedCard>
: :
<div className='flex flex-row justify-center w-full'>
{
<div className='flex flex-col md:flex-row justify-center w-full gap-8'>
{/* {
cards.map((item, index) => ( cards.map((item, index) => (
<CareerCard card={item} key={index} setExpanded={setIsComponentVisible} setExpandedCard={setExpandedCard} /> <CareerCard card={item} key={index} setExpanded={setIsComponentVisible} setExpandedCard={setExpandedCard} />
)) ))
}
} */}
<CareerCard card={cards.NetDev} setExpanded={setIsComponentVisible} setExpandedCard={setExpandedCard} />
{/* <CareerCard card={cards.NetDevIntern} setExpanded={setIsComponentVisible} setExpandedCard={setExpandedCard} /> */}


</div> </div>
} }

frontend/src/components/CareerCard.jsx → frontend/src/components/CareerCardsTemplates/CareerCard.jsx Целия файл

import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import net from './../assets/icons/net.svg';
import net from './../../assets/icons/net.svg';


const _card = { const _card = {
role: '.Net Developer', role: '.Net Developer',

+ 210
- 0
frontend/src/components/CareerCardsTemplates/ExpandedCard.jsx Целия файл

import React, { useContext, useEffect } from 'react';
import PropTypes from 'prop-types';
import TriangleButton from '../shared/TriangleButton';
import { useNavigate } from 'react-router-dom';
import net from './../../assets/icons/net.svg';
import { m } from 'framer-motion';
import useClickOutside from '../../hooks/useClickOutside';
import { UIContext } from '../../context';

const _data = {
requirements: [
'Good software development fundamentals and knowledge of .NET architecture concepts & patterns',
'Good knowledge of software design patterns',
'Good knowledge of databases and database design',
'Experience in working with microservices is a big plus',
'The ability to work in a big team but also to work independently',
'Excellent communication skills',
],
key: [
'Working as a full-stack developer on various project and products',
'Working with 3rd-party APIs',
'Working on different integration scenarios',
'Setting up project structure and architecture',
'Being involved in full project development, from writing a specification to deploying a finished product',
],
offer: [
'Full Remote position',
'A fast-growth company with stable projects and strong international clients',
'Opportunity to work in teams with experienced engineers',
'Competitive employment conditions',
'An environment that will make you feel good about your job',
'Challenging and diverse projects',
'Support in your personal and professional growth',
'Flexible working hours',
'Private health insurance',
],
};

const _card = {
role: '.Net Developer',
shortDetails:
'Team Diligent is constantly growing! We are looking for a team player that will work with experienced engineers. If technology is your passion and you are ready to move the boundaries of your knowledge every day, then, Diligent is the right place for you. If you are not from Niš, we are offering a full remote position.',
};

const ExpandedCard = ({ card, setExpanded, setExpandedCard }) => {
const linkTo = useNavigate();

const {uiContext, setUiContext} = useContext(UIContext);

useEffect(() => {
console.log(card);
}, [])

function handleContext(id) {
setUiContext({
...uiContext,
tab: id,
});
}

return (
<div
className={
'dark:text-white card-no-hover w-full h-fit shadow-md rounded-md px-12 lg:px-32 py-12 lg:py-16'
}
>
{card.templateFlag === 1 && (
<div className="flex flex-col items-start justify-center text-left">
<div className="flex flex-row items-center justify-start">
<div className="mr-4 lg:hidden">
<TriangleButton
onClick={() => {
setExpanded(false);
setExpandedCard({});
}}
direction={'left'}
/>
</div>
<div className="hidden lg:block absolute top-20 left-12">
<TriangleButton
onClick={() => {
setExpanded(false);
setExpandedCard({});
}}
direction={'left'}
/>
</div>

<img
src={net}
className="ml-auto mr-auto block w-[70px] bg-baby-blue text-dark-gray"
/>
<h3 className="ml-6 w-full font-semibold text-2xl">{card.role}</h3>
</div>
<p className="mt-6 text-sm">{card.extended.shortDetails}</p>
<h4 className="mt-6 font-semibold text-lg">Key Responsibilities:</h4>
<ul>
{_data.key.map((item, index) => (
<li className="list-disc ml-6" key={index}>
{item}
</li>
))}
</ul>
<br />
<h4 className="mt-6 font-semibold text-lg">Requirements:</h4>
<ul>
{_data.requirements.map((item, index) => (
<li className="list-disc ml-6" key={index}>
{item}
</li>
))}
</ul>
<br />
<h4 className="mt-6 font-semibold text-lg">What We Offer:</h4>
<ul>
{_data.offer.map((item, index) => (
<li className="list-disc ml-6" key={index}>
{item}
</li>
))}
</ul>
<br />
<div className="flex flex-row w-full items-center justify-end">
<a
href="/contact"
className="btn btn_primary mt-8 transition-all hover:transition-all"
onClick={()=> handleContext(card.id)}
>
Apply
</a>
</div>
</div>
)}
{card.templateFlag === 2 && (
<div className="flex flex-col items-start justify-center text-left">
<div className="flex flex-row items-center justify-start">
<div className="mr-4 lg:hidden">
<TriangleButton
onClick={() => {
setExpanded(false);
setExpandedCard({});
}}
direction={'left'}
/>
</div>
<div className="hidden lg:block absolute top-20 left-12">
<TriangleButton
onClick={() => {
setExpanded(false);
setExpandedCard({});
}}
direction={'left'}
/>
</div>

<img
src={net}
className="ml-auto mr-auto block w-[70px] bg-baby-blue text-dark-gray"
/>
<h3 className="ml-6 w-full font-semibold text-2xl">{card.role}</h3>
</div>
<p className="mt-6 text-sm">{card.extended.paragraph}</p>
<h4 className="mt-6 font-semibold text-lg">What We Offer:</h4>
<ul>
{card.extended.offer.map((item, index) => (
<li className="list-disc ml-6" key={index}>
{item}
</li>
))}
</ul>
<br />
<h4 className="mt-6 font-semibold text-lg">Requirements:</h4>
<ul>
{card.extended.requirements.map((item, index) => (
<li className="list-disc ml-6" key={index}>
{item}
</li>
))}
</ul>
<br />
<h4 className="mt-6 font-semibold text-lg">Our selection process has the following steps:</h4>
<ul>
{card.extended.selectionProcess.map((item, index) => (
<li className="list-decimal ml-6" key={index}>
{item}
</li>
))}
</ul>
<br />
<p className="mt-6 text-sm">{card.extended.conslusionParagraph}</p>
<br/>
<div className="flex flex-row w-full items-center justify-end">
<a
href="/contact"
className="btn btn_primary mt-8 transition-all hover:transition-all"
onClick={()=> handleContext(card.id)}
>
Apply
</a>
</div>
</div>
)}
</div>
);
};

ExpandedCard.propTypes = {};

export default ExpandedCard;

+ 0
- 108
frontend/src/components/ExpandedCard.jsx Целия файл

import React from 'react'
import PropTypes from 'prop-types'
import TriangleButton from './shared/TriangleButton';
import { useNavigate } from 'react-router-dom';
import net from './../assets/icons/net.svg';
import { m } from 'framer-motion';
import useClickOutside from '../hooks/useClickOutside';

const _data = {
requirements: [
'Good software development fundamentals and knowledge of .NET architecture concepts & patterns',
'Good knowledge of software design patterns',
'Good knowledge of databases and database design',
'Experience in working with microservices is a big plus',
'The ability to work in a big team but also to work independently',
'Excellent communication skills'
],
key: [
'Working as a full-stack developer on various project and products',
'Working with 3rd-party APIs',
'Working on different integration scenarios',
'Setting up project structure and architecture',
'Being involved in full project development, from writing a specification to deploying a finished product'
],
offer: [
'Full Remote position',
'A fast-growth company with stable projects and strong international clients',
'Opportunity to work in teams with experienced engineers',
'Competitive employment conditions',
'An environment that will make you feel good about your job',
'Challenging and diverse projects',
'Support in your personal and professional growth',
'Flexible working hours',
'Private health insurance'
],

}

const _card = {
role: '.Net Developer',
shortDetails: 'Team Diligent is constantly growing! We are looking for a team player that will work with experienced engineers. If technology is your passion and you are ready to move the boundaries of your knowledge every day, then, Diligent is the right place for you. If you are not from Niš, we are offering a full remote position.',

}

const ExpandedCard = ({card, setExpanded, setExpandedCard}) => {

const linkTo = useNavigate();

return (
<div
className={
'dark:text-white card-no-hover w-full h-fit shadow-md rounded-md px-12 lg:px-32 py-12 lg:py-16'
}
>
<div className="flex flex-col items-start justify-center text-left">
<div className="flex flex-row items-center justify-start">
<div className='mr-4 lg:hidden'>
<TriangleButton onClick={() => {setExpanded(false); setExpandedCard({})}} direction={'left'}/>
</div>
<div className='hidden lg:block absolute top-20 left-12'>
<TriangleButton onClick={() => {setExpanded(false); setExpandedCard({})}} direction={'left'}/>
</div>

<img
src={net}
className="ml-auto mr-auto block w-[70px] bg-baby-blue text-dark-gray"
/>
<h3 className="ml-6 w-full font-semibold text-2xl">{card.role}</h3>
</div>
<p className="mt-6 text-sm">{_card.shortDetails}</p>
<h4 className="mt-6 font-semibold text-lg">Key Responsibilities:</h4>
<ul>
{_data.key.map((item, index) => (
<li className='list-disc ml-6' key={index}>{item}</li>
))}
</ul>
<br />
<h4 className="mt-6 font-semibold text-lg">Requirements:</h4>
<ul>
{_data.requirements.map((item, index) => (
<li className='list-disc ml-6' key={index}>{item}</li>
))}
</ul>
<br />
<h4 className="mt-6 font-semibold text-lg">What We Offer:</h4>
<ul>
{_data.offer.map((item, index) => (
<li className='list-disc ml-6' key={index}>{item}</li>
))}
</ul>
<br />
<div className="flex flex-row w-full items-center justify-end">
<a
href="/contact"
className="btn btn_primary mt-8 transition-all hover:transition-all"
>
Apply
</a>
</div>
</div>
</div>
)
}

ExpandedCard.propTypes = {}

export default ExpandedCard

+ 22
- 0
frontend/src/components/Testimonials.jsx Целия файл

import TestimonialCard from './shared/TestimonialCard'; import TestimonialCard from './shared/TestimonialCard';
import Boza from './../assets/boza.jpg'; import Boza from './../assets/boza.jpg';
import Peter from './../assets/peter1.png'; import Peter from './../assets/peter1.png';
import Nick from './../assets/nick.jpg';
import ns from './../assets/ns.png'; import ns from './../assets/ns.png';


const _data = { const _data = {
clientImg: ns, clientImg: ns,
alt: 'Niš Ekspres', alt: 'Niš Ekspres',
}, },
{
clientName: 'Nick Pericle',
paragraph: `We've partnered with the team at Diligent Software for 3 years. We've built over a dozen apps together, and each time we're impressed by Diligent's dedicated approach, and end result. We consider Diligent Software a trusted partner - the trust we share, the flexibility, and the quality we get are just what we need. I can't recommend Diligent enough as a partner.`,
clientRole: 'VP of Operations @ Profit Optics',
clientImg: Nick,
alt: 'Nick',
},
], ],
}; };


imageAlt={_data.cards[2].alt} imageAlt={_data.cards[2].alt}
paragraph={_data.cards[2].paragraph} paragraph={_data.cards[2].paragraph}
/> />
<TestimonialCard
clientName={_data.cards[3].clientName}
clientRole={_data.cards[3].clientRole}
clientImg={_data.cards[3].clientImg}
imageAlt={_data.cards[3].alt}
paragraph={_data.cards[3].paragraph}
/>
</div> </div>
{/* {/*
<TestimonialCard/> <TestimonialCard/>
imageAlt={_data.cards[2].alt} imageAlt={_data.cards[2].alt}
paragraph={_data.cards[2].paragraph} paragraph={_data.cards[2].paragraph}
/> />
<TestimonialCard
clientName={_data.cards[3].clientName}
clientRole={_data.cards[3].clientRole}
clientImg={_data.cards[3].clientImg}
imageAlt={_data.cards[3].alt}
paragraph={_data.cards[3].paragraph}
/>
</FMCarousel> </FMCarousel>
)} )}
</div> </div>

+ 1
- 1
frontend/src/components/root/CustomLink.jsx Целия файл

// {context} // {context}
// </a> // </a>
<Link {...{ <Link {...{
className: 'flex gap-2 items-center px-[16px] py-[12px] text-p font-medium bg-[#8568BF] text-white rounded-full' ,
className: 'btn-primary w-fit items-center n-paragraph-title text-white rounded-[16px]' ,
to: href, to: href,
target: '_blank', target: '_blank',
...(downloadFile && {download: downloadFile}), ...(downloadFile && {download: downloadFile}),

+ 56
- 88
frontend/src/components/shared/ClientForm.jsx Целия файл

import React, { useRef } from 'react';
import TagInput from '../TagInput'; import TagInput from '../TagInput';
import img from '../../assets/images/Inqueries.png'; import img from '../../assets/images/Inqueries.png';
import * as Yup from 'yup'; import * as Yup from 'yup';
import { useContext, useState } from 'react'; import { useContext, useState } from 'react';
import * as emailjs from 'emailjs-com'; import * as emailjs from 'emailjs-com';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import ReactGA from 'react-ga4';
import ReCAPTCHA from 'react-google-recaptcha';
import axios from 'axios'; import axios from 'axios';


const api_url = 'http://localhost:1337';

export default function ClientForm() {
export default function ClientForm({ mg }) {
//search context for prevous entry TODO //search context for prevous entry TODO
const { clientForm, setClientForm } = useContext(ClientFormContext); const { clientForm, setClientForm } = useContext(ClientFormContext);
const [sucMsg, setSucMsg] = useState(false); const [sucMsg, setSucMsg] = useState(false);
const [errorMsg, setErrorMsg] = useState('');
const captchaRef = useRef(null);
const [msgText, setMsgText] = useState('');
const changeFormHandler = event => { const changeFormHandler = event => {
const { name, value } = event.target; const { name, value } = event.target;
setClientForm({ setClientForm({
<Formik <Formik
initialValues={clientForm} initialValues={clientForm}
validationSchema={validationSchema} validationSchema={validationSchema}
onSubmit={values => {
let data = {};

const fetchData = async () => {
axios.get(`${api_url}/api/client-submissions?filters[Email][$eq]=${values.email}`)
.then((res) => {
data = res.data.data[0];
if (typeof data == 'undefined') {
}
const submitDate = new Date(data.attributes.SubmitDate);
const now = new Date();
if ((now.getMonth() - submitDate.getMonth()) < 1)
{
setErrorMsg('You Already sent an email');
//console.log('email already sent');
return false;
}
else {
fetch(`${api_url}/api/client-submissions/${data.id}`, {
method: "PUT",
headers: {
"Content-type": "application/json; charset=UTF-8",
},
body: JSON.stringify({
data: {
SubmitDate: now,
}
})
}).then(r => r.json()).then(d => {
setErrorMsg('');
const val = {
Tag: values.tag,
Subject: values.subject,
Email: values.email,
Firstname: values.firstName,
Lastname: values.lastName,
Description: values.description,
}
// emailjs
// .send(
// process.env.REACT_APP_SERVICE_ID,
// process.env.REACT_APP_CLIENT_TEMPLATE_ID,
// val,
// process.env.REACT_APP_USER_ID,
// )
// .then(
// result => {
// console.log(result.text);
// setSucMsg(true);
// },
// error => {
// console.log(error.text);
// },
// );
}).catch(err => {
console.log(err)
return false
});
}
})
}
fetchData();
}}

onSubmit={async values => {
const data = {
Tag: values.tag,
Subject: values.subject,
Email: values.email,
Firstname: values.firstName,
Lastname: values.lastName,
Description: values.description,
};
const token = captchaRef.current.getValue();
captchaRef.current.reset();


if (token.length === 0) {
setSucMsg(true);
setMsgText('Please fill reCAPTCHA and try again. Thank you!');
} else {
await axios
.post(`${process.env.REACT_APP_CAPTCHA_API}/verify-token`, { token })
.then(res => {
setSucMsg(true);
if (res.data.data.success) {
setMsgText('Submission Succesful! Thank you!');
mg.messages.create('dilig.net', {
from: `${values.firstName} ${values.lastName} <${values.email}>`,
to: ['hr@dilig.net'],
subject: `${values.subject}`,
text: `${values.description}`,
html: `<p>${values.description}</p>`,
});
} else setMsgText('Please fill reCAPTCHA and try again. Thank you!');
})
.catch(error => {
console.log(error);
});
}
ReactGA.event('contact', {
category: 'Contact',
action: 'Business Inquiry',
});
}}
> >
{props => ( {props => (
<Form onSubmit={props.handleSubmit}> <Form onSubmit={props.handleSubmit}>
/> />
</div> </div>
</div> </div>

<div className="items-center justify-end flex">
<ReCAPTCHA
sitekey={process.env.REACT_APP_SITE_KEY}
ref={captchaRef}
/>
</div>
<div className=" py-3 text-right"> <div className=" py-3 text-right">
<button <button
type="submit" type="submit"
Submit Submit
</button> </button>
</div> </div>
{sucMsg && <div className={'text-sm text-right text-dg-primary-900'}>
Submission Succesful! Thank you!
</div> }
{errorMsg !== '' && <div className={'text-sm text-right text-red-700'}>
{errorMsg}
</div> }
{sucMsg && (
<div className={'text-sm text-right text-dg-primary-900'}>
{msgText}
</div>
)}
</div> </div>


<div className="col-span-1 sm:col-span-1 lg:col-span-1"></div> <div className="col-span-1 sm:col-span-1 lg:col-span-1"></div>

+ 29
- 6
frontend/src/components/shared/Contact.jsx Целия файл

import { JobFormContext } from '../../context'; import { JobFormContext } from '../../context';
import PageTitle from './PageTitle'; import PageTitle from './PageTitle';
import Wrapper from '../../layout/Wrapper'; import Wrapper from '../../layout/Wrapper';
import { UIContext } from './../../context/index';

import Mailgun from 'mailgun.js';
import FormData from 'form-data';

const mailgun = new Mailgun(FormData);
const mg = mailgun.client({
username: 'api',
key: process.env.REACT_APP_MAILGUN_API_KEY,
url: 'https://api.eu.mailgun.net',
});


export default function Contact(props) { export default function Contact(props) {
const [tab, setTab] = useState(true); const [tab, setTab] = useState(true);
//if (event.button !== 0) //if (event.button !== 0)
event.preventDefault(); event.preventDefault();
} }
const { uiContext, setUiContext } = useContext(UIContext);
const clientContext = useContext(ClientFormContext); const clientContext = useContext(ClientFormContext);
const jobContext = useContext(JobFormContext); const jobContext = useContext(JobFormContext);


<OrbitOnClick tab={tab} /> <OrbitOnClick tab={tab} />
</div> </div>
<div className="py-16 relative"> <div className="py-16 relative">
<div className="flex justify-end flex-col" >
<div className="flex justify-end flex-col">
<Tab.Group <Tab.Group
defaultIndex={props.defaultIndex} defaultIndex={props.defaultIndex}
onChange={index => handleTab(index)} onChange={index => handleTab(index)}
> >
<div className="flex flex-col md:flex-row items-start md:items-baseline md:justify-between" onMouseDown={handleTabClick}>
{tab ? <PageTitle left heading={"Tell Us About Your Idea!"} subheading={'Contact us'} /> : <PageTitle left heading={"Join Diligent!"} subheading={'Cotact us'} />}
<div
className="flex flex-col md:flex-row items-start md:items-baseline md:justify-between"
onMouseDown={handleTabClick}
>
{tab ? (
<PageTitle
left
heading={'Tell Us About Your Idea!'}
subheading={'Contact us'}
/>
) : (
<PageTitle left heading={'Join Diligent!'} subheading={'Cotact us'} />
)}

<Tab.List className="flex flex-row items-center md:flex-col lg:flex-row h-fit w-fit max-w-max md:ml-auto z-20 p-1 min-h-12 space-x-1 bg-dg-primary-400 rounded-xl my-4 align-middle"> <Tab.List className="flex flex-row items-center md:flex-col lg:flex-row h-fit w-fit max-w-max md:ml-auto z-20 p-1 min-h-12 space-x-1 bg-dg-primary-400 rounded-xl my-4 align-middle">
<Tab <Tab
className={({ selected }) => className={({ selected }) =>
<Tab.Panels className="w-full mt-2 mx-auto"> <Tab.Panels className="w-full mt-2 mx-auto">
<Tab.Panel className={classNames('py-3', 'outline-none')}> <Tab.Panel className={classNames('py-3', 'outline-none')}>
<ClientFormContext.Provider value={{ clientForm, setClientForm }}> <ClientFormContext.Provider value={{ clientForm, setClientForm }}>
<ClientForm />
<ClientForm mg={mg} />
</ClientFormContext.Provider> </ClientFormContext.Provider>
</Tab.Panel> </Tab.Panel>
<Tab.Panel className={classNames('py-3', 'outline-none')}> <Tab.Panel className={classNames('py-3', 'outline-none')}>
<JobForm <JobForm
cntCareers={cntCareers} cntCareers={cntCareers}
defaultPositionSelection={defaultPositionSelection} defaultPositionSelection={defaultPositionSelection}
mg={mg}
/> />
</JobFormContext.Provider> </JobFormContext.Provider>
</Tab.Panel> </Tab.Panel>

+ 46
- 0
frontend/src/components/shared/CookieBanner.jsx Целия файл

import '../../App.css';
import Wrapper from '../../layout/Wrapper';
import Cookie from './../../assets/Cookie.png';

const cookie_p =
'We use cookies to personalise content and ads, to provide social media features and to analyse our traffic. We also share information about your use of our site with our social media, advertising and analytics partners who may combine it with other information that you’ve provided to them or that they’ve collected from your use of their services.';

const CookieBanner = ({ handleAccept, handleDecline }) => {
return (
<Wrapper>
<div className="flex flex-row items-start gap-8 xl:mr-0 mr-4 md:p-8 px-2 py-4 isolate max-w-banner fixed bg-dg-primary-75 shadow-custom z-50 bottom-0 rounded-2xl mb-3">
<img
src={Cookie}
alt="Diligent Cookie"
className="hidden md:block w-44 h-48 flex-none z-0 grow-0 order-none"
/>
<div className="flex flex-col items-start p-0 gap-2.5 max-w-banner">
<div className="flex flex-col items-start p-0 gap-4 max-w-banner ">
<p className="md:text-title text-banner-mobile text-dark-gray font-secondary font-semibold">
Our Website uses Cookies
</p>
<p className="flex items-center text-dark-gray font-secondary md:text-banner-p text-banner-p-mobile">
{cookie_p}
</p>
</div>
<div className="max-w-banner w-full flex items-center justify-end p-0 md:gap-2.5">
<button
onClick={handleDecline}
className="flex items-start p-0 text-dg-primary-900 bg-dg-primary-75 font-semibold font-secondary md:px-64p px-42p md:py-20p py-15p md:w-max w-36 whitespace-nowrap"
>
DECLINE
</button>
<button
onClick={handleAccept}
className="btn-primary flex flex-row items-start md:px-64p px-42p md:py-20p py-15p md:w-max w-36 whitespace-nowrap"
>
Accept
</button>
</div>
</div>
</div>
</Wrapper>
);
};

export default CookieBanner;

+ 15
- 0
frontend/src/components/shared/GradientWrapper.jsx Целия файл

import React from 'react';

const GradientWrapper = ({ children, padding }) => {
return (
<div
className={
'px-[16px] md:px-0 bg-gradient-to-r from-[#90278F] to-[#8468BF]'
}
>
<div className={'max-w-custom md:text-center mx-auto flex flex-col gap-[16px]' + (padding ? ` ${padding}` : null) }>{children}</div>
</div>
);
};

export default GradientWrapper;

+ 1
- 1
frontend/src/components/shared/HashPositions.jsx Целия файл



const _data = { const _data = {
job: [{ job: [{
id:0,
id:1,
position: ".Net" position: ".Net"
}, },
] ]

+ 86
- 11
frontend/src/components/shared/JobForm.jsx Целия файл

import { useContext, useState, useRef, useEffect } from 'react'; import { useContext, useState, useRef, useEffect } from 'react';
import * as emailjs from 'emailjs-com'; import * as emailjs from 'emailjs-com';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import ReactGA from 'react-ga4';
import MyDropzone from './MyDropzone'; import MyDropzone from './MyDropzone';
import HashPositions from './HashPositions'; import HashPositions from './HashPositions';
<<<<<<< HEAD
import useDataApi from '../../hooks/useDataApi'; import useDataApi from '../../hooks/useDataApi';
import axios from 'axios'; import axios from 'axios';


const api_url = 'http://localhost:1337'; const api_url = 'http://localhost:1337';
=======
import ReCAPTCHA from 'react-google-recaptcha';
import axios from 'axios';
>>>>>>> staging


export default function JobForm(props) { export default function JobForm(props) {
const [sucMsg, setSucMsg] = useState(false); const [sucMsg, setSucMsg] = useState(false);
const captchaRef = useRef(null);
const [msgText, setMsgText] = useState('');
const cntCareersJobs = props.cntCareers; const cntCareersJobs = props.cntCareers;
let defaultPositionSelection = props.defaultPositionSelection; let defaultPositionSelection = props.defaultPositionSelection;
//search context for prevous entry TODO //search context for prevous entry TODO
const [otherInputState, setOtherInputState] = useState(true); const [otherInputState, setOtherInputState] = useState(true);
const [selectedPosition, setSelectedPosition] = useState(''); const [selectedPosition, setSelectedPosition] = useState('');
const [errorMsg, setErrorMsg] = useState(''); const [errorMsg, setErrorMsg] = useState('');
const [errorMsgPosition, setErrorMsgPosition] = useState('');
const fileInput = useRef(); const fileInput = useRef();


function changeFormHandler(event) { function changeFormHandler(event) {
.trim() .trim()
.min(2, 'Cover Letter too short') .min(2, 'Cover Letter too short')
.required('Cover Letter is Required'), .required('Cover Letter is Required'),
other: Yup.string(),
}); });


return ( return (
initialValues={jobForm} initialValues={jobForm}
validationSchema={validationSchema} validationSchema={validationSchema}
onChange={changeFormHandler} onChange={changeFormHandler}
<<<<<<< HEAD
onSubmit={values => { onSubmit={values => {


setSucMsg(false); setSucMsg(false);


//prep file //prep file
=======
onSubmit={async values => {
>>>>>>> staging
const prepFile = async file => { const prepFile = async file => {
if (file.size >= 2000000) { if (file.size >= 2000000) {
setErrorMsg('File too large!'); setErrorMsg('File too large!');
const convertBase64 = file => { const convertBase64 = file => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const fileReader = new FileReader(); const fileReader = new FileReader();
fileReader.readAsDataURL(file);


fileReader.readAsDataURL(file);
fileReader.onload = () => { fileReader.onload = () => {
resolve(fileReader.result); resolve(fileReader.result);
}; };
}; };
}); });
}; };
<<<<<<< HEAD


let data = {}; let data = {};


} }
=======
if (
selectedPosition === '' ||
(otherInputState === false && values.other === '')
)
setErrorMsgPosition('Position is Required');
else {
setErrorMsgPosition('');
if (jobForm.file === '') {
setErrorMsg('CV is Required');
} else {
setErrorMsg('');
if (jobForm.file.size >= 2000000) {
setErrorMsg('File too large!');
} else {
const file = {
filename: 'CV.pdf',
data: jobForm.file,
};

const token = captchaRef.current.getValue();
captchaRef.current.reset();
if (token.length === 0) {
setSucMsg(true);
setMsgText('Please fill reCAPTCHA and try again. Thank you!');
} else {
await axios
.post(`${process.env.REACT_APP_CAPTCHA_API}/verify-token`, {
token,
})
.then(res => {
setSucMsg(true);
if (res.data.data.success) {
setMsgText('Submission Succesful! Thank you!');

props.mg.messages.create('dilig.net', {
from: `${values.firstName} ${values.lastName} <${values.email}>`,
to: ['hr@dilig.net'],
subject: 'Applying for a position',
text: `Email: ${values.email}, Position:${values.position} ${values.other}, Cover letter: ${values.coverLetter}, Link: ${values.link} `,
html: `<p>Email: ${values.email}</p><p>Position: ${selectedPosition} ${values.other}</p><p>Cover letter: ${values.coverLetter}</p><p>Link (optional): ${values.link}</p>`,
attachment: file,
});
} else
setMsgText('Please fill reCAPTCHA and try again. Thank you!');
})
.catch(error => {
console.log(error);
});
}
}
}
>>>>>>> staging
} }
ReactGA.event('contact', {
category: 'Contact',
action: 'Job application',
});
}} }}
> >
{props => ( {props => (
onChange={props.handleChange} onChange={props.handleChange}
className="mt-1 disabled:bg-gray-100 disabled:border-gray-300 dark:disabled:bg-gray-400 dark:disabled:border-gray-600 focus:ring-dg-primary-600 focus:border-dg-primary-900 dark:bg-dg-primary-1500 dark:text-white block w-full shadow-sm sm:text-sm border-dg-primary-600 rounded-md transition duration-200" className="mt-1 disabled:bg-gray-100 disabled:border-gray-300 dark:disabled:bg-gray-400 dark:disabled:border-gray-600 focus:ring-dg-primary-600 focus:border-dg-primary-900 dark:bg-dg-primary-1500 dark:text-white block w-full shadow-sm sm:text-sm border-dg-primary-600 rounded-md transition duration-200"
/> />
</div>
{errorMsgPosition != '' ? (
<div className="h-4"> <div className="h-4">
<ErrorMessage
name="other"
component="div"
className="text-sm text-right text-red-600"
/>
<div className="text-sm text-right text-red-600">
{errorMsgPosition}
</div>
</div> </div>
</div>
) : null}
<div className="py-1"> <div className="py-1">
<label <label
htmlFor="first-name" htmlFor="first-name"
<div className="text-sm text-right">{errorMsg}</div> <div className="text-sm text-right">{errorMsg}</div>
</div> </div>
</div> </div>

<div className="items-center justify-end flex">
<ReCAPTCHA
sitekey={process.env.REACT_APP_SITE_KEY}
ref={captchaRef}
/>
</div>
<div className=" py-3 text-right"> <div className=" py-3 text-right">
<button <button
type="submit" type="submit"
</div> </div>
{sucMsg && ( {sucMsg && (
<div className={'text-sm text-right text-dg-primary-900'}> <div className={'text-sm text-right text-dg-primary-900'}>
Submission Succesful! Thank you!
{msgText}
</div> </div>
)} )}
</div> </div>

+ 4
- 5
frontend/src/components/shared/MyDropzone.jsx Целия файл

const [file, setFile] = useState(''); const [file, setFile] = useState('');
const [empty, setEmpty] = useState(true); const [empty, setEmpty] = useState(true);



function emptyFiles() { function emptyFiles() {
const newFile = []; const newFile = [];
setFile(newFile); setFile(newFile);
</svg> </svg>
); );


const onDrop = useCallback(acceptedFiles => {
const onDrop = useCallback(async acceptedFiles => {
if (acceptedFiles && acceptedFiles.length > 0) { if (acceptedFiles && acceptedFiles.length > 0) {
if (acceptedFiles[0] !== 'undefined' && acceptedFiles[0].type !== 'undefined') { if (acceptedFiles[0] !== 'undefined' && acceptedFiles[0].type !== 'undefined') {
if (acceptedFiles[0].type === 'application/pdf') { if (acceptedFiles[0].type === 'application/pdf') {
acceptedFiles.map(file => {
setFile(file);
});
const files = Array.from(acceptedFiles);
const fileBuffer = await files[0];
setFile(fileBuffer);
setEmpty(false); setEmpty(false);
} }
} }

+ 1
- 1
frontend/src/components/shared/PageTitle.jsx Целия файл

import React from "react"; import React from "react";
import PropTypes from 'prop-types' import PropTypes from 'prop-types'


const PageTitle = ({heading, subheading, left, color,pb}) => {
const PageTitle = ({heading, subheading, left, color, pb }) => {
return ( return (
<div className={"flex flex-col gap-8p"+ (left ? " text-left items-start":" text-center items-center") + (color ? " text-[#9B32CE]" : " ") + (pb ? ' pb-2' :' ')}> <div className={"flex flex-col gap-8p"+ (left ? " text-left items-start":" text-center items-center") + (color ? " text-[#9B32CE]" : " ") + (pb ? ' pb-2' :' ')}>
<h6 className={"subheading" + (left ? " text-left":" text-center")}>{subheading}</h6> <h6 className={"subheading" + (left ? " text-left":" text-center")}>{subheading}</h6>

+ 21
- 0
frontend/src/components/shared/PageTitleOneFont.jsx Целия файл

import React from "react";
import PropTypes from 'prop-types'

const PageTitleOneFont = ({heading, subheading, left, color, pb }) => {
return (
<div className={"flex flex-col gap-8p"+ (left ? " text-left items-start":" text-center items-center") + (color ? " text-[#9B32CE]" : " ") + (pb ? ' pb-2' :' ')}>
<h6 className={"n-subheading" + (left ? " text-left":" text-center")}>{subheading}</h6>
<h1 className={"n-heading" + (left ? " text-left":" text-center")}>{heading}</h1>
</div>
)
}

PageTitleOneFont.propTypes = {
heading: PropTypes.string,
subheading: PropTypes.string,
left: PropTypes.bool,
color: PropTypes.bool,
}

export default PageTitleOneFont;


+ 33
- 0
frontend/src/components/shared/ReactHelmet.jsx Целия файл

import { Helmet } from 'react-helmet-async';
import PropTypes from 'prop-types';
import '../../styles/cards.css';

const api_url = process.env.REACT_APP_API_URL;

const ReactHelmet = ({ seo }) => {
console.log(seo);
return (
<Helmet>
<title>{seo.metaTitle}</title>
<meta name="description" content={seo.metaDescription} />
<link rel="canonical" href={seo.canonicalURL} />
<meta name="keywords" content={seo.keywords} />
<meta name="viewport" content={seo.metaViewport} />
<meta name="robots" content={seo.metaRobots} />
<meta property="og:title" content={seo.metaSocial[0].title} />
<meta
property="og:image"
content={`${api_url}${seo.metaSocial[0].image.data.attributes.url}`}
/>
<meta property="og:description" content={seo.metaSocial[0].description} />
<meta property="twitter:title" content={seo.metaSocial[1].title} />
<meta
property="twitter:image"
content={`${api_url}${seo.metaSocial[1].image.data.attributes.url}`}
/>
<meta property="twitter:description" content={seo.metaSocial[1].description} />
</Helmet>
);
};

export default ReactHelmet;

+ 2
- 1
frontend/src/context/index.js Целия файл

}); });


export const UIContext = React.createContext({ export const UIContext = React.createContext({
tab: '',
tab: true,
contactRef: '', contactRef: '',
position: 0,
}) })

+ 10
- 13
frontend/src/hooks/useAnalytics.js Целия файл

import React, { useEffect } from "react";
import { useLocation } from "react-router-dom";
import { useEffect } from 'react';
import { useCookies } from 'react-cookie';
import ReactGA from 'react-ga4';


const useAnalytics = () => {
const location = useLocation();

useEffect(() => {
window.gtag('event', 'page_view', {
page_title: document.title,
page_path: location.pathname + location.search,
page_location: window.location.href
})
}, [location]);
}
const useAnalytics = pageTitle => {
const [cookies] = useCookies(['user']);
useEffect(() => {
if (cookies.diligent_ga === 'true')
ReactGA.send({ hitType: 'pageview', page: pageTitle });
}, []);
};


export default useAnalytics; export default useAnalytics;

+ 17
- 0
frontend/src/hooks/useDataApi.js Целия файл

isError: false, isError: false,
data: initialData, data: initialData,
}); });
//getData
useEffect(() => {
const fetchData = async () => {
dispatch({ type: 'FETCH_INIT' });
try {
const result = await axios(url);
dispatch({ type: 'FETCH_SUCCESS', payload: result.data.data.attributes });
} catch (error) {
dispatch({ type: 'FETCH_FAILURE' });
}
};
fetchData();
}, [url]);


useEffect(() => { useEffect(() => {
let didCancel = false; let didCancel = false;

+ 8
- 6
frontend/src/index.js Целия файл

import './index.css'; import './index.css';
import App from './App'; import App from './App';
import reportWebVitals from './reportWebVitals'; import reportWebVitals from './reportWebVitals';
import { CookiesProvider } from 'react-cookie';
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom';
import { HelmetProvider } from 'react-helmet-async';


if (module.hot) module.hot.accept()

if (module.hot) module.hot.accept();


ReactDOM.render( ReactDOM.render(
<React.StrictMode> <React.StrictMode>
<BrowserRouter> <BrowserRouter>
<App />
<CookiesProvider>
<HelmetProvider>
<App />
</HelmetProvider>
</CookiesProvider>
</BrowserRouter> </BrowserRouter>
</React.StrictMode>, </React.StrictMode>,
document.getElementById('root'), document.getElementById('root'),
); );




// If you want to start measuring performance in your app, pass a function // If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log)) // to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals

+ 35
- 3
frontend/src/pages/About.jsx Целия файл

import TimelineCardsWrapper2 from '../components/TimelineWrapper2'; import TimelineCardsWrapper2 from '../components/TimelineWrapper2';
import TimelineLogo from '../components/TimelineLogo'; import TimelineLogo from '../components/TimelineLogo';
import PageLayout from '../layout/PageLayout'; import PageLayout from '../layout/PageLayout';
//import useAnalytics from '../hooks/useAnalytics';
import useAnalytics from '../hooks/useAnalytics';
import ReactHelmet from '../components/shared/ReactHelmet';

const _data = { const _data = {
heading: { heading: {
subheading: 'About Us', subheading: 'About Us',
}, },
}; };


const api_url = process.env.REACT_APP_API_URL;

export default function About() { export default function About() {
const [cnt, setCnt] = useState('');
const [isLoaded, setIsLoaded] = useState('');


useEffect(() => {
useEffect(async () => {
document.title = 'About Us'; document.title = 'About Us';
var vid = document.getElementById('animation');
vid.playbackRate = 2;
await axios
.get(
`${api_url}/api/aboutpage?populate[0]=SEO&populate[1]=SEO.metaSocial&populate[2]=SEO.metaImage&populate[3]=SEO.metaSocial.image`,
)
.then(res => {
setCnt(res.data.data.attributes);
setIsLoaded(true);
})
.catch(err => {
console.log(err);
setIsLoaded(false);
});
}, []); }, []);


//useAnalytics();
useAnalytics('About Us');

if (!isLoaded) {
return (
<div className="z-50 w-full h-screen bg-white dark:bg-dg-primary-1700 dark:text-white flex items-center justify-center text-3xl font-semibold">
<video id="animation" width="540" height="540" autoPlay muted loop>
<source src={Animation_Diligent} type="video/webm" />
Loading...
</video>
</div>
);
}


return ( return (
<PageLayout> <PageLayout>
{cnt.SEO && <ReactHelmet seo={cnt.SEO} />}
<div className="bg-white dark:bg-dg-primary-1700 w-full pt-32"> <div className="bg-white dark:bg-dg-primary-1700 w-full pt-32">
{/* Heading Section */} {/* Heading Section */}
<section <section

+ 83
- 34
frontend/src/pages/Careers.jsx Целия файл

import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import axios from 'axios'; import axios from 'axios';


import CardCareers from '../components/CardCareers';
import Contact from '../components/shared/Contact';

import Animation_Diligent from '../assets/animation_diligent.webm'; import Animation_Diligent from '../assets/animation_diligent.webm';
import Wrapper from '../layout/Wrapper'; import Wrapper from '../layout/Wrapper';
import PageTitle from '../components/shared/PageTitle'; import PageTitle from '../components/shared/PageTitle';
import CardLife from '../components/shared/CardLife'; import CardLife from '../components/shared/CardLife';
import ActionCard from '../components/shared/ActionCard'; import ActionCard from '../components/shared/ActionCard';
import AboutUsSlider from '../components/shared/AboutUsSlider'; import AboutUsSlider from '../components/shared/AboutUsSlider';
import CardCareers2 from '../components/CardCareers2';
import CardCareers2 from '../components/CareerCardsTemplates/CardCareers2';
import OrbitOnScroll from '../components/shared/graphics/OrbitOnScroll'; import OrbitOnScroll from '../components/shared/graphics/OrbitOnScroll';
import PageLayout from '../layout/PageLayout'; import PageLayout from '../layout/PageLayout';
//import useAnalytics from '../hooks/useAnalytics';
import useAnalytics from '../hooks/useAnalytics';


// eslint-disable-next-line no-underscore-dangle // eslint-disable-next-line no-underscore-dangle
const _data = { const _data = {
subheading: 'Careers', subheading: 'Careers',
}, },
job: { job: {
cards: [
{
nugget: '.Net',
role: '.Net Developer',
shortDetails:
'An idea solves a problem. We help you to create that idea, build a product and scale it to be successful in your business.',
NetDev: {
id: 1,
templateFlag: 1,
role: '.Net Developer',
nugget: '.Net',
shortDetails:
'An idea solves a problem. We help you to create that idea, build a product and scale it to be successful in your business.',
extended: {
paragraph:
'Team Diligent is constantly growing! We are looking for a team player that will work with experienced engineers. If technology is your passion and you are ready to move the boundaries of your knowledge every day, then, Diligent is the right place for you. If you are not from Niš, we are offering a full remote position.',
requirements: [
'Good software development fundamentals and knowledge of .NET architecture concepts & patterns',
'Good knowledge of software design patterns',
'Good knowledge of databases and database design',
'Experience in working with microservices is a big plus',
'The ability to work in a big team but also to work independently',
'Excellent communication skills',
],
key: [
'Working as a full-stack developer on various project and products',
'Working with 3rd-party APIs',
'Working on different integration scenarios',
'Setting up project structure and architecture',
'Being involved in full project development, from writing a specification to deploying a finished product',
],
offer: [
'Full Remote position',
'A fast-growth company with stable projects and strong international clients',
'Opportunity to work in teams with experienced engineers',
'Competitive employment conditions',
'An environment that will make you feel good about your job',
'Challenging and diverse projects',
'Support in your personal and professional growth',
'Flexible working hours',
'Private health insurance',
],
}, },
],
},
// NetDevIntern: {
// id: 2,
// templateFlag: 2,
// role: '.Net Developer Internship',
// nugget: '.NetInernship',
// shortDetails:
// 'An idea solves a problem. We help you to create that idea, build a product and scale it to be successful in your business.',
// extended: {
// paragraph:
// 'Team Diligent is constantly growing! We are looking for a team player that will work with experienced engineers. If technology is your passion and you are ready to move the boundaries of your knowledge every day, then, Diligent is the right place for you. If you are not from Niš, we are offering a full remote position.',
// offer: [
// 'Paid internship',
// 'Full Remote position',
// 'A fast-growth company with stable projects and strong international clients',
// 'Experience of working in a team',
// 'Work on real project with real clients',
// 'Mentorship from industry leaders',
// 'Support in your personal and professional growth',
// 'Lots of team activities and perks',
// 'Modern working place with a positive and fun atmosphere',
// ],
// requirements: [
// 'Fundamentals of data structures ',
// 'Fundamentals and knowledge of .NET architecture concepts & patterns',
// 'Fundamentals of databases and database design',
// 'Team player and fast learner',
// 'Analytical and problem-solving skills',
// ],
// selectionProcess: [
// 'Application',
// 'CV Screening',
// 'HR Interview',
// 'Technical Interview',
// 'Internship - offer & contract',
// ],
// conslusionParagraph:
// 'At the end of the selection process, we will select interns able to join our team for a 3 months internship and arrange the beginning of the practice personally with you.',
// },
// },
}, },
life: { life: {
heading: 'A Culture That’s Serious About Work and Fun', heading: 'A Culture That’s Serious About Work and Fun',


const api_url = process.env.REACT_APP_API_URL; const api_url = process.env.REACT_APP_API_URL;



useEffect(() => { useEffect(() => {
document.title = 'Careers'; document.title = 'Careers';
}, []); }, []);


//useAnalytics();
useAnalytics('Careers');


useEffect(async () => { useEffect(async () => {
var vid = document.getElementById('animation'); var vid = document.getElementById('animation');
className="flex items-center justify-center max-w-custom m-auto" className="flex items-center justify-center max-w-custom m-auto"
> >
<div className="w-full"> <div className="w-full">
{/* {cntCareers.job.map(job => (
<div key={job.id}>
<CardCareers
image={job.icon.data.attributes.url}
heading={job.heading}
paragraph={job.paragraph}
requirements_heading={job.requirements_heading}
requirements_paragraph={job.requirements_paragraph}
expectations_heading={job.expectations_heading}
expectations_paragraph={job.expectations_paragraph}
benefits_heading={job.benefits_heading}
benefits_paragraph={job.benefits_paragraph}
hash_position={job.position}
setClickedPosition={setClickedPosition}
/>
</div>
))} */}
<CardCareers2 cards={_data.job.cards} />
<CardCareers2 cards={_data.job} />
</div> </div>
</section> </section>
</Wrapper> </Wrapper>
<div className='mt-90p'>
<Wrapper bg padding={' py-90p'}> <Wrapper bg padding={' py-90p'}>
<PageTitle <PageTitle
left left
</section> </section>
</div> </div>
</Wrapper> </Wrapper>
</div>
<Wrapper padding={' py-90p'}> <Wrapper padding={' py-90p'}>
<PageTitle heading={_data.connect.heading} color /> <PageTitle heading={_data.connect.heading} color />
<p className="paragraph my-32p">{_data.connect.paragraph}</p> <p className="paragraph my-32p">{_data.connect.paragraph}</p>

+ 141
- 140
frontend/src/pages/CaseStudy.jsx Целия файл

import ActionCard from '../components/shared/ActionCard'; import ActionCard from '../components/shared/ActionCard';
//import useAnalytics from '../hooks/useAnalytics';
import useAnalytics from '../hooks/useAnalytics';
import PageLayout from '../layout/PageLayout'; import PageLayout from '../layout/PageLayout';
import { useEffect } from 'react'; import { useEffect } from 'react';


export default function CaseStudy() { export default function CaseStudy() {
useEffect(() => { useEffect(() => {
document.title = 'Case Studies'; document.title = 'Case Studies';
},[]);
}, []);

useAnalytics('Case Studies');


//useAnalytics();
return ( return (
<PageLayout> <PageLayout>
<div className="bg-baby-blue dark:bg-dg-primary-1700 w-full pt-20 md:pt-24">
{/* Heading Section */}
<section
id="heading"
className="flex flex-col items-center justify-center m-auto py-16 md:py-32 bg-[url('https://images.unsplash.com/photo-1619252584172-a83a949b6efd')] bg-fixed bg-cover"
>
<div className="my-8 flex flex-col md:flex-row justify-start items-center w-full max-w-custom px-8 xl:px-0">
<div className="w-full">
<h6 className="subheading">Case Study</h6>
<h1 className="heading text-dg-secondary mt-2">BI Healthcare Solution </h1>
<p className="paragraph mt-4">
BI Solution that provides an uncommon level of insights into the healing
process.
</p>
<div className="bg-baby-blue dark:bg-dg-primary-1700 w-full pt-20 md:pt-24">
{/* Heading Section */}
<section
id="heading"
className="flex flex-col items-center justify-center m-auto py-16 md:py-32 bg-[url('https://images.unsplash.com/photo-1619252584172-a83a949b6efd')] bg-fixed bg-cover"
>
<div className="my-8 flex flex-col md:flex-row justify-start items-center w-full max-w-custom px-8 xl:px-0">
<div className="w-full">
<h6 className="subheading">Case Study</h6>
<h1 className="heading text-dg-secondary mt-2">BI Healthcare Solution </h1>
<p className="paragraph mt-4">
BI Solution that provides an uncommon level of insights into the healing
process.
</p>
</div>
</div> </div>
</div>
</section>
</section>


{/* About the Client Section */}
<section id="client" className="flex flex-col items-center justify-center mt-16">
<div className="my-8 flex flex-col md:flex-row justify-center items-start w-full max-w-custom m-auto px-8 xl:px-0">
<div className="w-full md:w-1/2">
<h3 className="h3-heading text-teal-600">About the Client</h3>
<p className="paragraph mt-4">
Healthcare company has a centralized IT solution for tracking every aspect
of their own business, especially services provided to clients and working
times of their clinicians in all clinics they own all around the USA.
</p>
</div>
<div className="w-full md:w-1/2 grid grid-cols-2 md:grid-cols-3 gap-16 mt-8 md:mt-0">
<div className="hidden md:inline-block"></div>
<div className="float-left md:float-right text-left md:text-right">
<h5 className="text-teal-600 font-semibold">Country</h5>
<p className="mt-4">USA</p>
{/* About the Client Section */}
<section id="client" className="flex flex-col items-center justify-center mt-16">
<div className="my-8 flex flex-col md:flex-row justify-center items-start w-full max-w-custom m-auto px-8 xl:px-0">
<div className="w-full md:w-1/2">
<h3 className="h3-heading text-teal-600">About the Client</h3>
<p className="paragraph mt-4">
Healthcare company has a centralized IT solution for tracking every aspect
of their own business, especially services provided to clients and working
times of their clinicians in all clinics they own all around the USA.
</p>
</div> </div>
<div className="float-left md:float-right text-left md:text-right">
<h5 className="text-teal-600 font-semibold">Industry</h5>
<p className="mt-4">Healthcare</p>
<div className="w-full md:w-1/2 grid grid-cols-2 md:grid-cols-3 gap-16 mt-8 md:mt-0">
<div className="hidden md:inline-block"></div>
<div className="float-left md:float-right text-left md:text-right">
<h5 className="text-teal-600 font-semibold">Country</h5>
<p className="mt-4">USA</p>
</div>
<div className="float-left md:float-right text-left md:text-right">
<h5 className="text-teal-600 font-semibold">Industry</h5>
<p className="mt-4">Healthcare</p>
</div>
</div> </div>
</div> </div>
</div>
</section>

{/* Domain Section */}
<section id="domain" className="flex flex-col items-center justify-center mt-16">
<div className="my-8 flex flex-col justify-center items-center w-full max-w-custom m-auto px-8 xl:px-0">
<div className="w-full">
<h3 className="h3-heading">Domain</h3>
<p className="paragraph mt-4">
BI Solution helps clinicians to improve their work and create a wider
picture of client progress during the healing process. The solution offers
our customers a high level of insight into their cash flows and workforce
organization. In one word, this is a fully customizable solution for a
comprehensive business process.
</p>
</div>
</div>
</section>
</section>


{/* Challanges, Solution Section */}
<section
id="challanges_solution"
className="flex flex-col items-center justify-center mt-16"
>
<div className="my-8 flex flex-col md:flex-row justify-center items-center w-full max-w-custom m-auto px-8 xl:px-0">
<div className="w-full md:w-1/2 md:pr-16">
<div>
<h3 className="h3-heading">Challanges</h3>
<p className="text-sm text-dark-gray dark:text-white mt-4">
The main objective is to create a solution that meets the requirements of
stakeholders while integrating with existing IT systems to get data
without impacting the system. The solution should use only an MS stack of
technologies while taking care of sensitive data, and maintaining and
providing up-to-date data. The solution should also be a comfortable and
reliable, user-friendly solution for everyday work.
</p>
</div>
<div className="mt-8">
<h3 className="h3-heading">Solution</h3>
<p className="text-sm text-dark-gray dark:text-white mt-4">
The purpose of interactive data visualization is to allow users to explore
and understand data. We used the Power BI analytics service to accomplish
this. Azure has several features that automate data processing and ensure
the reliability and security of the data.
{/* Domain Section */}
<section id="domain" className="flex flex-col items-center justify-center mt-16">
<div className="my-8 flex flex-col justify-center items-center w-full max-w-custom m-auto px-8 xl:px-0">
<div className="w-full">
<h3 className="h3-heading">Domain</h3>
<p className="paragraph mt-4">
BI Solution helps clinicians to improve their work and create a wider
picture of client progress during the healing process. The solution offers
our customers a high level of insight into their cash flows and workforce
organization. In one word, this is a fully customizable solution for a
comprehensive business process.
</p> </p>
</div> </div>
</div> </div>
<img
src="https://drive.google.com/uc?export=view&id=1TDOQDUkH4dDnjx2x5DJkDpi5xEHrbCvS"
alt="Case Study main image"
className="text-center w-full md:w-1/2"
/>
</div>
</section>
</section>


{/* Results Section */}
<section id="results" className="flex flex-col items-center justify-center mt-16">
<div className="my-8 flex flex-col justify-center items-center w-full max-w-custom m-auto px-8 xl:px-0">
<div className="w-full">
<h3 className="h3-heading text-dg-secondary">Results</h3>
<ul className="list-disc paragraph mt-2 pl-8">
<li>Visualize information to ensure better data understanding </li>
<li>
Deliver the product within an established amount of time and defined
budgets
</li>
<li> Be up to date with the latest stack of technologies</li>
<li>
Offer services from ETL with complex data processing to data visualization
</li>
</ul>
{/* Challanges, Solution Section */}
<section
id="challanges_solution"
className="flex flex-col items-center justify-center mt-16"
>
<div className="my-8 flex flex-col md:flex-row justify-center items-center w-full max-w-custom m-auto px-8 xl:px-0">
<div className="w-full md:w-1/2 md:pr-16">
<div>
<h3 className="h3-heading">Challanges</h3>
<p className="text-sm text-dark-gray dark:text-white mt-4">
The main objective is to create a solution that meets the requirements
of stakeholders while integrating with existing IT systems to get data
without impacting the system. The solution should use only an MS stack
of technologies while taking care of sensitive data, and maintaining and
providing up-to-date data. The solution should also be a comfortable and
reliable, user-friendly solution for everyday work.
</p>
</div>
<div className="mt-8">
<h3 className="h3-heading">Solution</h3>
<p className="text-sm text-dark-gray dark:text-white mt-4">
The purpose of interactive data visualization is to allow users to
explore and understand data. We used the Power BI analytics service to
accomplish this. Azure has several features that automate data
processing and ensure the reliability and security of the data.
</p>
</div>
</div>
<img
src="https://drive.google.com/uc?export=view&id=1TDOQDUkH4dDnjx2x5DJkDpi5xEHrbCvS"
alt="Case Study main image"
className="text-center w-full md:w-1/2"
/>
</div> </div>
</div>
</section>
</section>


{/* Technologies Section */}
<section
id="technologies"
className="flex flex-col items-center justify-center mt-16"
>
<div className="my-8 flex flex-col justify-center items-center w-full max-w-custom m-auto px-8 xl:px-0">
<div className="w-full">
<h3 className="h3-heading">Technologies</h3>
{/* Results Section */}
<section id="results" className="flex flex-col items-center justify-center mt-16">
<div className="my-8 flex flex-col justify-center items-center w-full max-w-custom m-auto px-8 xl:px-0">
<div className="w-full">
<h3 className="h3-heading text-dg-secondary">Results</h3>
<ul className="list-disc paragraph mt-2 pl-8">
<li>Visualize information to ensure better data understanding </li>
<li>
Deliver the product within an established amount of time and defined
budgets
</li>
<li> Be up to date with the latest stack of technologies</li>
<li>
Offer services from ETL with complex data processing to data
visualization
</li>
</ul>
</div>
</div> </div>
<div className="grid grid-cols-4 justify-center justify-items-center gap-8 xl:flex xl:flex-row items-center xl:justify-start xl:gap-16 w-full mt-8">
{technologies.map(technology => (
<img
key={technology.id}
src={technology.link}
alt="Technology's image"
className="w-12 md:w-16 lg:w-20"
/>
))}
</section>

{/* Technologies Section */}
<section
id="technologies"
className="flex flex-col items-center justify-center mt-16"
>
<div className="my-8 flex flex-col justify-center items-center w-full max-w-custom m-auto px-8 xl:px-0">
<div className="w-full">
<h3 className="h3-heading">Technologies</h3>
</div>
<div className="grid grid-cols-4 justify-center justify-items-center gap-8 xl:flex xl:flex-row items-center xl:justify-start xl:gap-16 w-full mt-8">
{technologies.map(technology => (
<img
key={technology.id}
src={technology.link}
alt="Technology's image"
className="w-12 md:w-16 lg:w-20"
/>
))}
</div>
</div> </div>
</div>
</section>
</section>


{/* CTA Section */}
<section id="cta" className="flex flex-col items-center justify-center mt-16">
<div className="px-8 mt-8 mb-32 w-full max-w-custom">
<ActionCard
title="Let's Work Together!"
text="Business Intelligence portal which enhouses series of web applications & reporting tools used for in-depth analysis on product pricing, money flow, resources, employees, etc. Applications provide administrative users overview, as well as detail look scaled down to individual product."
btn1="More Projects"
btn2="Contact Us"
link1={'/portfolio'}
link2={'/contact'}
/>
</div>
</section>
</div>
{/* CTA Section */}
<section id="cta" className="flex flex-col items-center justify-center mt-16">
<div className="px-8 mt-8 mb-32 w-full max-w-custom">
<ActionCard
title="Let's Work Together!"
text="Grow faster with a dedicated team of .NET & JS experts."
btn1="More Projects"
btn2="Contact Us"
link1={'/portfolio'}
link2={'/contact'}
/>
</div>
</section>
</div>
</PageLayout> </PageLayout>
); );
} }

+ 13
- 5
frontend/src/pages/CaseStudyBI.jsx Целия файл

import Wrapper from '../layout/Wrapper'; import Wrapper from '../layout/Wrapper';
import TechNuggets from '../components/shared/TechNuggets'; import TechNuggets from '../components/shared/TechNuggets';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
//import useAnalytics from '../hooks/useAnalytics';
import useAnalytics from '../hooks/useAnalytics';


const numbers = [ const numbers = [
{ {
}; };


export default function CaseStudyBI() { export default function CaseStudyBI() {
useEffect(() => { useEffect(() => {
document.title = 'Case Study: BI Healthcare Solution'; document.title = 'Case Study: BI Healthcare Solution';
}, []); }, []);


//useAnalytics();
useAnalytics('Case Study: BI Healthcare Solution');


return ( return (
<PageLayout> <PageLayout>
<h3 className="h3-heading">Technologies</h3> <h3 className="h3-heading">Technologies</h3>
</div> </div>
<TechNuggets <TechNuggets
tech={['Azure Data Factory','Azure SQL Server', 'Microsoft Power BI', '.Net Core', 'Azure App Services', 'Microsoft Power Automate','Azure Logic Apps','Azure Active Directory']}
tech={[
'Azure Data Factory',
'Azure SQL Server',
'Microsoft Power BI',
'.Net Core',
'Azure App Services',
'Microsoft Power Automate',
'Azure Logic Apps',
'Azure Active Directory',
]}
/> />
</div> </div>
</section> </section>
<div className="px-8 mt-8 mb-32 w-full max-w-custom"> <div className="px-8 mt-8 mb-32 w-full max-w-custom">
<ActionCard <ActionCard
title="Let's Work Together!" title="Let's Work Together!"
text="Business Intelligence portal which enhouses series of web applications & reporting tools used for in-depth analysis on product pricing, money flow, resources, employees, etc. Applications provide administrative users overview, as well as detail look scaled down to individual product."
text="Grow faster with a dedicated team of .NET & JS experts."
btn1="More Projects" btn1="More Projects"
btn2="Contact Us" btn2="Contact Us"
link1={'/portfolio'} link1={'/portfolio'}

+ 24
- 26
frontend/src/pages/CaseStudyCentralized.jsx Целия файл

import Wrapper from '../layout/Wrapper'; import Wrapper from '../layout/Wrapper';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import TechNuggets from '../components/shared/TechNuggets'; import TechNuggets from '../components/shared/TechNuggets';
//import useAnalytics from '../hooks/useAnalytics';
import useAnalytics from '../hooks/useAnalytics';


const numbers = [ const numbers = [
{ {
challanges: { challanges: {
heading: 'Challanges', heading: 'Challanges',
paragraph: paragraph:
"Some of them didn't even have open API-s, some of them required an extra set of rules, and some of them were still in development. This made integration difficult and time-consuming. However, we were eventually able to overcome these challenges and provide our users with a seamless experience.",
"Some of our biggest challenges were connected with the actual diversity of systems that we needed to integrate. Some of them didn't even have open API-s, some required an extra set of rules, and some were still in development. This made integration difficult and time-consuming. However, we were eventually able to overcome these challenges and provide our users with a seamless experience.",
}, },


solution: { solution: {
}; };


export default function CaseStudyCentralized() { export default function CaseStudyCentralized() {
useEffect(() => { useEffect(() => {
document.title = 'Case Study: Centralized Monitoring System'; document.title = 'Case Study: Centralized Monitoring System';
}, []); }, []);


//useAnalytics();
useAnalytics('Case Study: Centralized Monitoring System');


return ( return (
<PageLayout> <PageLayout>
</div> </div>
</section> </section>


<Wrapper padding={' py-90p'}>
<motion.section
id="status-numbers"
className="flex flex-col md:flex-row items-start justify-between w-full gap-90p px-90p"
initial={{ y: 60, opacity: 0 }}
whileInView={{ y: 0, opacity: 1 }}
transition={{ duration: 0.5, ease: 'easeOut' }}
>
{numbers.map((item, i) => (
<div key={i} className="flex flex-col">
<h2 className="display-number text-center">
{item.value}{item.static}
</h2>
<h3 className="number-title text-center">
{item.title}
</h3>
</div>
))}
</motion.section>
</Wrapper>
<Wrapper padding={' py-90p'}>
<motion.section
id="status-numbers"
className="flex flex-col md:flex-row items-start justify-between w-full gap-90p px-90p"
initial={{ y: 60, opacity: 0 }}
whileInView={{ y: 0, opacity: 1 }}
transition={{ duration: 0.5, ease: 'easeOut' }}
>
{numbers.map((item, i) => (
<div key={i} className="flex flex-col">
<h2 className="display-number text-center">
{item.value}
{item.static}
</h2>
<h3 className="number-title text-center">{item.title}</h3>
</div>
))}
</motion.section>
</Wrapper>


{/* About the Client Section */} {/* About the Client Section */}
<section id="client" className="flex flex-col items-center justify-center mt-16"> <section id="client" className="flex flex-col items-center justify-center mt-16">
<div className="w-full"> <div className="w-full">
<h3 className="h3-heading">Technologies</h3> <h3 className="h3-heading">Technologies</h3>
</div> </div>
<TechNuggets tech={['.Net','MS SQL Server','JQuery','Power BI']} />
<TechNuggets tech={['.Net', 'MS SQL Server', 'JQuery', 'Power BI']} />
</div> </div>
</section> </section>


<div className="px-8 mt-8 mb-32 w-full max-w-custom"> <div className="px-8 mt-8 mb-32 w-full max-w-custom">
<ActionCard <ActionCard
title="Let's Work Together!" title="Let's Work Together!"
text="Business Intelligence portal which enhouses series of web applications & reporting tools used for in-depth analysis on product pricing, money flow, resources, employees, etc. Applications provide administrative users overview, as well as detail look scaled down to individual product."
text="Grow faster with a dedicated team of .NET & JS experts."
btn1="More Projects" btn1="More Projects"
btn2="Contact Us" btn2="Contact Us"
link1={'/portfolio'} link1={'/portfolio'}

+ 12
- 6
frontend/src/pages/CaseStudyFinantial.jsx Целия файл

import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import Wrapper from '../layout/Wrapper'; import Wrapper from '../layout/Wrapper';
import TechNuggets from '../components/shared/TechNuggets'; import TechNuggets from '../components/shared/TechNuggets';
//import useAnalytics from '../hooks/useAnalytics';
import useAnalytics from '../hooks/useAnalytics';
const numbers = [ const numbers = [
{ {
value: 5, value: 5,
document.title = 'Case Study: Financial Engine'; document.title = 'Case Study: Financial Engine';
}, []); }, []);


//useAnalytics();
useAnalytics('Case Study: Financial Engine');


return ( return (
<PageLayout> <PageLayout>
</div> </div>
</section> </section>


{/* Technologies Section */}
<section id="technologies" className="flex flex-col mt-16">
{/* Technologies Section */}
<section id="technologies" className="flex flex-col mt-16">
<div className="my-8 flex flex-col w-full max-w-custom m-auto px-8 xl:px-0"> <div className="my-8 flex flex-col w-full max-w-custom m-auto px-8 xl:px-0">
<div className="w-full"> <div className="w-full">
<h3 className="h3-heading">Technologies</h3> <h3 className="h3-heading">Technologies</h3>
</div> </div>
<TechNuggets <TechNuggets
tech={['.Net','Service-Oriented Architecture (SOA)', 'MS SQL Server', 'MS MVC', 'Event-Driven Architecture (EDA)']}
tech={[
'.Net',
'Service-Oriented Architecture (SOA)',
'MS SQL Server',
'MS MVC',
'Event-Driven Architecture (EDA)',
]}
/> />
</div> </div>
</section> </section>
<div className="px-8 mt-8 mb-32 w-full max-w-custom"> <div className="px-8 mt-8 mb-32 w-full max-w-custom">
<ActionCard <ActionCard
title="Let's Work Together!" title="Let's Work Together!"
text="Business Intelligence portal which enhouses series of web applications & reporting tools used for in-depth analysis on product pricing, money flow, resources, employees, etc. Applications provide administrative users overview, as well as detail look scaled down to individual product."
text="Grow faster with a dedicated team of .NET & JS experts."
btn1="More Projects" btn1="More Projects"
btn2="Contact Us" btn2="Contact Us"
link1={'/portfolio'} link1={'/portfolio'}

+ 4
- 8
frontend/src/pages/CaseStudyResource.jsx Целия файл

import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import Wrapper from '../layout/Wrapper'; import Wrapper from '../layout/Wrapper';
import TechNuggets from '../components/shared/TechNuggets'; import TechNuggets from '../components/shared/TechNuggets';
//import useAnalytics from '../hooks/useAnalytics';
import useAnalytics from '../hooks/useAnalytics';


const numbers = [ const numbers = [
{ {
}; };


export default function CaseStudyResource() { export default function CaseStudyResource() {


useEffect(() => { useEffect(() => {
document.title = 'Case Study: Resource Planning System'; document.title = 'Case Study: Resource Planning System';
}, []); }, []);


//useAnalytics();
useAnalytics('Case Study: Resource Planning System');


return ( return (
<PageLayout> <PageLayout>
<div className="w-full"> <div className="w-full">
<h3 className="h3-heading">Technologies</h3> <h3 className="h3-heading">Technologies</h3>
</div> </div>
<TechNuggets
tech={['.Net', 'MS SQL Server', 'React Native', 'React.JS']}
/>
<TechNuggets tech={['.Net', 'MS SQL Server', 'React Native', 'React.JS']} />
</div> </div>
</section> </section>


<div className="px-8 mt-8 mb-32 w-full max-w-custom"> <div className="px-8 mt-8 mb-32 w-full max-w-custom">
<ActionCard <ActionCard
title="Let's Work Together!" title="Let's Work Together!"
text="Business Intelligence portal which enhouses series of web applications & reporting tools used for in-depth analysis on product pricing, money flow, resources, employees, etc. Applications provide administrative users overview, as well as detail look scaled down to individual product."
text="Grow faster with a dedicated team of .NET & JS experts."
btn1="More Projects" btn1="More Projects"
btn2="Contact Us" btn2="Contact Us"
link1={'/portfolio'} link1={'/portfolio'}

+ 5
- 8
frontend/src/pages/CaseStudyStrata.jsx Целия файл

import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import Wrapper from '../layout/Wrapper'; import Wrapper from '../layout/Wrapper';
import TechNuggets from '../components/shared/TechNuggets'; import TechNuggets from '../components/shared/TechNuggets';
//import useAnalytics from '../hooks/useAnalytics';
import useAnalytics from '../hooks/useAnalytics';


const numbers = [ const numbers = [
{ {
}; };


export default function CaseStudyStrata() { export default function CaseStudyStrata() {

useEffect(() => { useEffect(() => {
document.title = 'Case Study: Healthcare Tracking Software'; document.title = 'Case Study: Healthcare Tracking Software';
}, []); }, []);


//useAnalytics();
useAnalytics('Case Study: Healthcare Tracking Software');
return ( return (
<PageLayout> <PageLayout>
<div className="bg-baby-blue dark:bg-dg-primary-1700 w-full pt-20 md:pt-24"> <div className="bg-baby-blue dark:bg-dg-primary-1700 w-full pt-20 md:pt-24">
<div className="w-full"> <div className="w-full">
<h3 className="h3-heading">Technologies</h3> <h3 className="h3-heading">Technologies</h3>
</div> </div>
<TechNuggets
tech={['C#', 'MVC', 'SQL','Ajax','React Native']}
/>
<TechNuggets tech={['C#', 'MVC', 'SQL', 'Ajax', 'React Native']} />
</div> </div>
</section> </section>


<div className="px-8 mt-8 mb-32 w-full max-w-custom"> <div className="px-8 mt-8 mb-32 w-full max-w-custom">
<ActionCard <ActionCard
title="Let's Work Together!" title="Let's Work Together!"
text="Business Intelligence portal which enhouses series of web applications & reporting tools used for in-depth analysis on product pricing, money flow, resources, employees, etc. Applications provide administrative users overview, as well as detail look scaled down to individual product."
text="Grow faster with a dedicated team of .NET & JS experts."
btn1="More Projects" btn1="More Projects"
btn2="Contact Us" btn2="Contact Us"
link1={'/portfolio'} link1={'/portfolio'}

+ 6
- 11
frontend/src/pages/CaseStudyTicketing.jsx Целия файл

import { useEffect } from 'react'; import { useEffect } from 'react';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import TechNuggets from '../components/shared/TechNuggets'; import TechNuggets from '../components/shared/TechNuggets';
//import useAnalytics from '../hooks/useAnalytics';
import useAnalytics from '../hooks/useAnalytics';
const numbers = [ const numbers = [
{ {
value: 10, value: 10,
challanges: { challanges: {
heading: 'Challanges', heading: 'Challanges',
paragraph: paragraph:
'There are many different types of applications based on a platform where they will be executed. There is a lot of specific hardware system (ex. Cameras, Barcode scanner, etc.) that needed to be connected with some parts of our system. Data between components must be shared in real-time.',
'There are many different types of applications based on a platform where they will be executed. There are a lot of specific hardware systems (ex. Cameras, Barcode scanner, etc.) that needed to be connected with some parts of our system. Data between components must be shared in real-time.',
}, },


solution: { solution: {
list: [ list: [
{ {
id: 1, id: 1,
text: 'Uploading documents for every case and for every hearing',
text: 'Innovations introduced with the latest hardware in the industry',
}, },
{ {
id: 2, id: 2,
}; };


export default function CaseStudyTicketing() { export default function CaseStudyTicketing() {

useEffect(() => { useEffect(() => {
document.title = 'Case Study: Ticketing System For Passengers'; document.title = 'Case Study: Ticketing System For Passengers';
}, []); }, []);


//useAnalytics();
useAnalytics('Case Study: Ticketing System For Passengers');


return ( return (
<PageLayout> <PageLayout>
</section> </section>


{/* Technologies Section */} {/* Technologies Section */}
<section
id="technologies"
className="flex flex-col mt-16"
>
<section id="technologies" className="flex flex-col mt-16">
<div className="my-8 flex flex-col w-full max-w-custom m-auto px-8 xl:px-0"> <div className="my-8 flex flex-col w-full max-w-custom m-auto px-8 xl:px-0">
<div className="w-full"> <div className="w-full">
<h3 className="h3-heading">Technologies</h3> <h3 className="h3-heading">Technologies</h3>
<div className="px-8 mt-8 mb-32 w-full max-w-custom"> <div className="px-8 mt-8 mb-32 w-full max-w-custom">
<ActionCard <ActionCard
title="Let's Work Together!" title="Let's Work Together!"
text="Business Intelligence portal which enhouses series of web applications & reporting tools used for in-depth analysis on product pricing, money flow, resources, employees, etc. Applications provide administrative users overview, as well as detail look scaled down to individual product."
text="Grow faster with a dedicated team of .NET & JS experts."
btn1="More Projects" btn1="More Projects"
btn2="Contact Us" btn2="Contact Us"
link1={'/portfolio'} link1={'/portfolio'}

+ 8
- 4
frontend/src/pages/ContactPage.jsx Целия файл

import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import Contact from '../components/shared/Contact'; import Contact from '../components/shared/Contact';
import { UIContext } from '../context';
import PageLayout from '../layout/PageLayout'; import PageLayout from '../layout/PageLayout';
//import useAnalytics from '../hooks/useAnalytics';
import useAnalytics from '../hooks/useAnalytics';


function ContactPage() { function ContactPage() {
const [data, setData] = useState(''); const [data, setData] = useState('');
const [isLoaded, setIsLoaded] = useState(''); const [isLoaded, setIsLoaded] = useState('');



useEffect(() => { useEffect(() => {
document.title = 'Contact Us'; document.title = 'Contact Us';
}, []); }, []);

useAnalytics('Contact Us');

return ( return (
<PageLayout> <PageLayout>
<section id="contact" className="h-fit bg-baby-blue dark:bg-dg-primary-1600 mt-90p"> <section id="contact" className="h-fit bg-baby-blue dark:bg-dg-primary-1600 mt-90p">
<h1 className="hidden">Contact us: Tell Us about Your Idea!</h1> <h1 className="hidden">Contact us: Tell Us about Your Idea!</h1>
<Contact defaultIndex={0} />
<UIContext.Provider value={UIContext}>
<Contact />
</UIContext.Provider>
</section> </section>
</PageLayout> </PageLayout>
); );

+ 22
- 3
frontend/src/pages/Home.jsx Целия файл

import PageLayout from '../layout/PageLayout'; import PageLayout from '../layout/PageLayout';
import MapDilig from '../components/Map'; import MapDilig from '../components/Map';
import useDataApi from '../hooks/useDataApi'; import useDataApi from '../hooks/useDataApi';
import useAnalytics from '../hooks/useAnalytics';
import ReactHelmet from '../components/shared/ReactHelmet';


const api_url = process.env.REACT_APP_API_URL; const api_url = process.env.REACT_APP_API_URL;
// const fieldArray = [
// 'landing',
// 'why',
// 'why.heading',
// 'why.card_left.icon',
// 'why.card_mid.icon',
// 'why.card_right.icon',
// 'landing.heading',
// 'SEO',
// 'SEO.metaSocial',
// 'SEO.metaImage',
// 'SEO.metaSocial.image',
// ];




const strapiPopulate = [ const strapiPopulate = [
return stringQuery; return stringQuery;
}; };


export default function Home({forwardedRef}) {
export default function Home({ forwardedRef }) {
const [cnt, setCnt] = useState(''); const [cnt, setCnt] = useState('');
const [landingData, setLandingData] = useState(null); const [landingData, setLandingData] = useState(null);
const [cardData, setCardData] = useState(null); const [cardData, setCardData] = useState(null);
const [{ data, isLoading, isError }, doFetch] = useDataApi( const [{ data, isLoading, isError }, doFetch] = useDataApi(
`${api_url}/api/w-home-page?${stringBuilder()}`, `${api_url}/api/w-home-page?${stringBuilder()}`,
); );
const [contactElement, setContactElement] = useState(0);

useAnalytics('Home page');


useEffect(() => { useEffect(() => {
document.title = 'Diligent Software'; document.title = 'Diligent Software';
} else { } else {
return ( return (
<PageLayout> <PageLayout>
{cnt.SEO && <ReactHelmet seo={cnt.SEO} />}
<div className="bg-white dark:bg-dg-primary-1700 w-full pt-32 overflow-hidden"> <div className="bg-white dark:bg-dg-primary-1700 w-full pt-32 overflow-hidden">
{/* <FormSwitch /> */} {/* <FormSwitch /> */}


</Tab.Group> */} </Tab.Group> */}


{/* Landing Section */} {/* Landing Section */}
{data && <Landing heading={data.Heading} numbers={data.HeroNumbers.number} button={data.button} paragraph={data.paragraph} />}
<Landing data={cnt.landing.heading} />


{/* Why Us Section */} {/* Why Us Section */}
{data && <WhySection heading={data.WhyUsHeading} cards={data.Cards} p1={data.WhyUsParagraph1} p2={data.WhyUsParagraph2} />}
<WhySection data={cnt.why} />


{/* Our Services Section */} {/* Our Services Section */}
{/* <ServicesHome /> */} {/* <ServicesHome /> */}

+ 34
- 3
frontend/src/pages/Portfolio.jsx Целия файл

import PageLayout from '../layout/PageLayout'; import PageLayout from '../layout/PageLayout';


import StrataThumb from './../assets/images/CaseStudy/StrataThumb.jpg'; import StrataThumb from './../assets/images/CaseStudy/StrataThumb.jpg';
//import useAnalytics from '../hooks/useAnalytics';
import useAnalytics from '../hooks/useAnalytics';
import ReactHelmet from '../components/shared/ReactHelmet';


const _data = { const _data = {
heading: { heading: {
], ],
}; };


const api_url = process.env.REACT_APP_API_URL;

export default function Portfolio() { export default function Portfolio() {
const [cnt, setCnt] = useState('');
const [isLoaded, setIsLoaded] = useState('');


useEffect(() => {
useEffect(async () => {
document.title = 'Case Studies'; document.title = 'Case Studies';
var vid = document.getElementById('animation');
vid.playbackRate = 2;
await axios
.get(
`${api_url}/api/portfoliopage?populate[0]=SEO&populate[1]=SEO.metaSocial&populate[2]=SEO.metaImage&populate[3]=SEO.metaSocial.image`,
)
.then(res => {
setCnt(res.data.data.attributes);
setIsLoaded(true);
})
.catch(err => {
console.log(err);
setIsLoaded(false);
});
}, []); }, []);


//useAnalytics();
useAnalytics('Case Studies');

if (!isLoaded) {
return (
<div className="z-50 w-full h-screen bg-white dark:bg-dg-primary-1700 dark:text-white flex items-center justify-center text-3xl font-semibold">
<video id="animation" width="540" height="540" autoPlay muted loop>
<source src={Animation_Diligent} type="video/webm" />
Loading...
</video>
</div>
);
}


return ( return (
<PageLayout> <PageLayout>
{cnt.SEO && <ReactHelmet seo={cnt.SEO} />}
<div className="flex flex-col gap-90p pt-32"> <div className="flex flex-col gap-90p pt-32">
<Wrapper> <Wrapper>
<h1 className="hidden">Our Work - Case Studies</h1> <h1 className="hidden">Our Work - Case Studies</h1>

+ 7
- 10
frontend/src/pages/ProcessPage.jsx Целия файл

import ProcessFacelessSlider from '../components/shared/ProcessFacelessSlider'; import ProcessFacelessSlider from '../components/shared/ProcessFacelessSlider';
import useWindowSize from '../hooks/useWindowSize'; import useWindowSize from '../hooks/useWindowSize';
import ProcessSlider from '../components/ProcessSlider'; import ProcessSlider from '../components/ProcessSlider';
//import useAnalytics from '../hooks/useAnalytics';
import useAnalytics from '../hooks/useAnalytics';


const _data = { const _data = {
heading: { heading: {
ActionCard: { ActionCard: {
heading: 'Let’s Work Together!', heading: 'Let’s Work Together!',
paragraph: paragraph:
'Business Intelligence portal which enhouses series of web applications & reporting tools used for in-depth analysis on product pricing, money flow, resources, employees, etc. Applications provide administrative users overview, as well as detail look scaled down to individual product.',
'Grow faster with a dedicated team of .NET & JS experts.',
primaryBtn: 'Contact Us', primaryBtn: 'Contact Us',
secondaryBtn: 'Portfolio', secondaryBtn: 'Portfolio',
}, },
}; };


const ProcessPage = () => { const ProcessPage = () => {

const [isMobile, setIsMobile] = useState(false); const [isMobile, setIsMobile] = useState(false);


const windowInfo = useWindowSize(); const windowInfo = useWindowSize();
document.title = 'Process'; document.title = 'Process';
}, []); }, []);


//useAnalytics();
useAnalytics('Process');


useEffect(() => { useEffect(() => {
if (windowInfo.width < 1000)
setIsMobile(true);
else
setIsMobile(false);
},[windowInfo]);
if (windowInfo.width < 1000) setIsMobile(true);
else setIsMobile(false);
}, [windowInfo]);


return ( return (
<PageLayout> <PageLayout>
</div> */} </div> */}
<div className="relative mx-auto my-32p md:my-90p"> <div className="relative mx-auto my-32p md:my-90p">
{!isMobile ? ( {!isMobile ? (
<div className="w-full">
<div className="flex w-full">
<ProcessSvg className="" /> <ProcessSvg className="" />
</div> </div>
) : ( ) : (

+ 257
- 199
frontend/src/pages/WorkWithUs.jsx Целия файл

import React, { Children, useEffect } from 'react'
import { Link } from 'react-router-dom'
import CustomLink from '../components/root/CustomLink'
import TertiaryButton from '../components/root/TertiaryButton'
import ActionCard from '../components/shared/ActionCard'
import CardLife from '../components/shared/CardLife'
import PageHeading from '../components/shared/PageHeading'
import PageTitle from '../components/shared/PageTitle'
import Testimonials from '../components/Testimonials'
//import useAnalytics from '../hooks/useAnalytics'
import Wrapper from '../layout/Wrapper'
import {ReactComponent as DownalodIcon } from './../assets/download-icon.svg'
import {ReactComponent as BusIcon } from './../assets/icons/workwithus/bus.svg'
import {ReactComponent as FintechIcon } from './../assets/icons/workwithus/empty-wallet-tick.svg'
import {ReactComponent as HospitalIcon } from './../assets/icons/workwithus/hospital.svg'
import {ReactComponent as SchoolIcon } from './../assets/icons/workwithus/teacher.svg'
import React, { Children, Fragment, useEffect } from 'react';
import CustomLink from '../components/root/CustomLink';
import ActionCard from '../components/shared/ActionCard';


const _data = {
downloadIcon: '',
downloadFilePath: `${process.env.PUBLIC_URL}/DiligentCompanyOverview.pdf`,
downloadFileName: 'Diligent Company Overview.pdf',
problems: [
{
id:1,
title:'Lack of dedication and long-term commitment',
paragraph:'More often than not, our clients come to realize that the only familiar face they see from the company to which they outsource is the account manager. Technical staff fluctuates, hampering team cohesion, and preventing meaningful progress and team growth - there’s little valuable knowledge accumulation in the team.'
},
{
id:2,
title:'Resources are unable to scale with what the company needs',
paragraph:'Dynamic of the business environment demands from our clients the ability to perform a fast-paced scale up and down of their tech teams. The delays introduced due to lack of available resources, or lack of appropriate resources, prolong the development process or stop it altogether. Inability to quickly scale down impacts the budget, flexibility in responding to unforeseen market conditions, and fast repurposing of resources. ',
},
{
id:3,
title:'Lack of quality tech-staff that wouldn’t break a bank',
paragraph:'Our clients are unable to onboard enough high-quality tech resources to cover all their needs . The two main reasons for this are lack of available high-quality resources and the cost of those resources.',
}
],
help: [
{
id:1,
title:'We outsource for a company, not a project',
paragraph:'All of our resources are dedicated to a single client. We provide the conditions, and expect them to put all their focus into understanding the whole of the client’s business - from high level to the details. This approach allows for knowledge accumulation and increase in value of their contribution with time.'
},
{
id:2,
title:'Long term, dedicated engineers',
paragraph:'Related to the previous point, our relationships with the clients tend to be very long-term. We have, where the relationship was long enough, the same resources onboarded with the same client for more than a decade. Our resources are more a part of the client’s company then they are of Diligent - Diligent is just the venue allowing them to do their job. ',
},
{
id:3,
title:'Jump right in - we know our domains',
paragraph:'Diligent’s resources, in business domains where we have accumulated experience, are capable of quickly producing high-value contributions to our clients. We know the concepts, we are familiar with the processes, we’ve faced the problems and solved them. If faced with something new - we’ll learn and do it quickly.'
},
{
id:4,
title:'Competitive prices',
paragraph:'Diligent provides a low entry price for our new clients until proven as a valuable partner. Even afterwards, once we’ve shown what we can do and contribute meaningfully to our client’s business, we tend to operate with lower fees than our competitors. Simply ask us for a bid or a pricing table and we’ll show you.'
}
]
import useDataApi from '../hooks/useDataApi';
import Animation_Diligent from '../assets/animation_diligent.webm';
import Wrapper from '../layout/Wrapper';


import PageLayout from '../layout/PageLayout';
import PageTitleOneFont from '../components/shared/PageTitleOneFont';
import GradientWrapper from '../components/shared/GradientWrapper';

import '../App.css';
import useAnalytics from './../hooks/useAnalytics';

const api_url = process.env.REACT_APP_API_URL;

const download = {
downloadFilePath: `${process.env.PUBLIC_URL}/DiligentCompanyOverview.pdf`,
downloadFileName: 'Diligent Company Overview.pdf',
}; };


const Segment = ({children}) => {
return (
<div className='py-[48px] mx-auto w-full text-center'>
{children}
</div>
);
}
const strapiPopulate = [
'Heading',
'Heading.subtitle',
'Heading.title',
'Problems',
'Highlighted',
'Highlighted.title',
'Highlighted.paragraph',
'WhyWork',
'WhyWork.img',
'Stats',
'SucessParagraph',
'Spec',
'Download',
'OfficeImg',
'WorkTogether',
];


const TechCard = ({children}) => {
return (
<div className='rounded-[8px] bg-white py-[24px] px-[32px] items-center justify-center text-center'>
{children}
</div>
)
}
const HelpParagraph = ({title, paragraph}) => {
const stringBuilder = () => {
let stringQuery = '';
strapiPopulate.map((item, index) => {
if (index !== 0) stringQuery += '&';
stringQuery += `populate=${item}`;
});
return stringQuery;
};

const NumberIcon = ({ number }) => {
return ( return (
<div>
<h4 className='font-semibold text-title'>{title}</h4>
<p>{paragraph}</p>
<div className="bg-baby-blue rounded-[6px] h-[48px] w-[48px] flex justify-center items-center text-center font-semibold text-dg-primary-900 text-n-h3-heading-mobile md:n-h3-heading">
<h4>{number}.</h4>
</div> </div>
)
}
);
};


const WorkWithUs = () => { const WorkWithUs = () => {
//useAnalytics();
useAnalytics('Work With Us');

const [{ data, isLoading, isError }, doFetch] = useDataApi(
`${api_url}/api/work-with-us-page?${stringBuilder()}`,
);


useEffect(() => { useEffect(() => {
document.title = 'Work With Us'; document.title = 'Work With Us';
},[]);
}, []);


return (
<div className='mt-90p'>
<Wrapper padding={' py-[48px]'}>
<PageTitle heading={'Diligent at a Glance'} subheading={'work with us'} />
</Wrapper>
<div className='flex flex-col md:flex gap-[32px] w-fit mx-auto'>
<CustomLink href={_data.downloadFilePath} downloadFile={_data.downloadFileName} context={'Company Overview'}>
<p>Company Overview</p>
<DownalodIcon/>
</CustomLink>
</div>
<Segment>
<p>Our clients primarily come from one of the following 4 business domains:</p>
</Segment>
<Wrapper bg padding={' py-[48px]'}>
<div className='flex grid grid-cols-2 lg:grid-cols-4 gap-32p items-center justify-center mx-auto'>
<TechCard>
<FintechIcon className='mx-auto'/>
<p>Fintech</p>
</TechCard>
<TechCard>
<HospitalIcon className='mx-auto'/>
<p>Healthcare</p>
</TechCard>
<TechCard>
<BusIcon className='mx-auto'/>
<p>Transportation</p>
</TechCard>
<TechCard>
<SchoolIcon className='mx-auto'/>
<p>Education</p>
</TechCard>
</div>
</Wrapper>
<Wrapper padding={' py-[48px]'}>
<p className='pb-32p max-w-[1000px] mx-auto'>Within those domains, our customers range from startups (11.2 Ventures), over small and medium sized companies (Gold Bullion International, Intellum…), to Fortune 500 companies (Henry Schein…).</p>
<p className='max-w-[1000px] mx-auto'>Decision to outsource the whole, or a part, of software development accompanied with a demand for personal, long-term, dedication and responsibility is common for our clients. Most of them have already had some experience with other outsourcing companies, or are in active relationships with other outsourcing companies, when they decide to give us a try.</p>
</Wrapper>
<Wrapper padding={' py-[48px]'}>
<h4 className='font-semibold font-secondary text-[#9B32CE] text-subtitle-48 text-center w-full'>What Are Their Problems?</h4>
</Wrapper>
<Wrapper >
<section>
<div className="flex flex-col justify-center items-start w-full max-w-custom m-auto px-8 xl:px-0 mb-[90px]">
<div className="flex flex-col gap-32p w-full max-w-[950px] mx-auto">
{_data.problems.map((item, index) => (
<CardLife
key={index}
number={item.id}
heading={item.title}
paragraph={item.paragraph}
/>
if (isLoading) {
return (
<div className="z-50 w-full h-screen bg-white dark:bg-dg-primary-1700 overflow-hidden dark:text-white flex items-center justify-center text-3xl font-semibold">
<video id="animation" width="540" height="540" autoPlay muted loop>
<source src={Animation_Diligent} type="video/webm" />
Loading...
</video>
</div>
);
} else {
return (
<PageLayout>
<div className="mt-[48px] md:mt-[180px]">
<Wrapper padding={' py-[48px]'}>
{data ? (
<Fragment>
<PageTitleOneFont
heading={data.Heading.title}
subheading={data.Heading.subtitle}
left
/>
<p className="mt-[16px] mr-0 md:mr-[400px] n-paragraph">
{data.HeadingParagraph}
</p>
</Fragment>
) : null}
</Wrapper>
<div className="mx-auto md:mx-2/5 pb-90p">
<Wrapper padding={' md:py-[48px]'}>
{data ? (
<h2 className="n-h3-heading md:text-center">{data.ProblemsTitle}</h2>
) : null}
</Wrapper>

<Wrapper padding={' py-[48px]'}>
{data ? (
<div className="flex flex-col gap-90p max-w-[860px] mx-auto">
{data.Problems.map((item, index) => (
<div key={index} className="flex flex-col md:flex-row gap-[32px]">
<div>
<NumberIcon number={index + 1} />
</div>
<div className="flex flex-col gap-[4px]">
<h6 className="n-paragraph-title">{item.title}</h6>
<p className="n-paragraph">{item.paragraph}</p>
</div>
</div>
))} ))}
</div> </div>
) : null}
</Wrapper>
</div>
{data ? (
<GradientWrapper padding={'py-32p md:py-90p'}>
<h6 className="n-h3-heading text-white">{data.Highlighted.title}</h6>
<p className="n-paragraph text-white md:max-w-[800px] mx-0 md:mx-auto">
{data.Highlighted.paragraph}
</p>
</GradientWrapper>
) : null}
{data ? (
<Wrapper padding={' py-[32px] md:py-[200px]'}>
<div className="flex flex-col gap-[64px] md:gap-[120px]">
{data.WhyWork.map((item, index) => (
<div
key={index}
className={
(index % 2
? 'flex flex-col md:flex-row-reverse '
: 'flex flex-col md:flex-row ') +
'w-full justify-between items-center gap-[24px] md:gap-0'
}
>
<div>
<img src={api_url + item.img.data.attributes.url}></img>
</div>
<div className="flex flex-col gap-[8px] md:gap-[16px] max-w-[520px]">
<h6 className="n-h3-heading text-dark-gray">{item.title}</h6>
<p className="n-paragraph">{item.paragraph}</p>
</div>
</div>
))}
</div>
</Wrapper>
) : null}
{data ? (
<GradientWrapper padding={'py-32p md:py-90p'}>
<div className="max-w-custom flex flex-col md:flex-row md:justify-between gap-[64px] md:gap-0">
{data.Stats.map((item, index) => (
<div key={index} className="flex flex-col gap-[8px] text-center">
<h6 className="n-heading text-white">{item.value}</h6>
<p className="n-paragraph-title text-white">{item.title}</p>
</div>
))}
</div>
</GradientWrapper>
) : null}
<Wrapper padding={' py-[48px] md:py-[200px]'}>
{data ? (
<div className="flex flex-col gap-[16px]">
<h6 className="n-h3-heading text-dark-gray">{data.SuccessTitle}</h6>
{data.SucessParagraph.map((item, index) => (
<p key={index} className="n-paragraph">
{item.ParagraphElement}
</p>
))}
</div>
) : null}
</Wrapper>
<div className="mx-auto md:mx-2/5 pb-90p">
<Wrapper padding={' md:py-[48px]'}>
{data ? (
<h6 className="n-h3-heading md:text-center text-dark-gray">
{data.SpecTitle}
</h6>
) : null}
</Wrapper>

<Wrapper padding={' py-[48px]'}>
{data ? (
<div className="flex flex-col sm:flex-row gap-[48px] mx-auto justify-center z-10 opacity-100 font-semibold">
<div className="flex flex-col gap-32p sm:mb-8">
<div className="bg-white py-32p px-[24px] rounded-[8px] text-center shadow-[0_3px_10px_rgb(0,0,0,0.2)]">
{data.Spec[0].title}
</div>
<div className="bg-white py-32p px-[24px] rounded-[8px] text-center shadow-[0_3px_10px_rgb(0,0,0,0.2)]">
{data.Spec[1].title}
</div>
<div className="bg-white py-32p px-[24px] rounded-[8px] text-center shadow-[0_3px_10px_rgb(0,0,0,0.2)]">
{data.Spec[2].title}
</div>
</div>
<div className="flex flex-col gap-32p sm:mt-8">
<div className="bg-white py-32p px-[24px] rounded-[8px] text-center shadow-[0_3px_10px_rgb(0,0,0,0.2)]">
{data.Spec[3].title}
</div>
<div className="bg-white py-32p px-[24px] rounded-[8px] text-center shadow-[0_3px_10px_rgb(0,0,0,0.2)]">
{data.Spec[4].title}
</div>
<div className="bg-white py-32p px-[24px] rounded-[8px] text-center shadow-[0_3px_10px_rgb(0,0,0,0.2)]">
{data.Spec[5].title}
</div>
</div>
<div className="flex flex-col gap-32p sm:mb-8">
<div className="bg-white py-32p px-[24px] rounded-[8px] text-center shadow-[0_3px_10px_rgb(0,0,0,0.2)]">
{data.Spec[6].title}
</div>
<div className="bg-white py-32p px-[24px] rounded-[8px] text-center shadow-[0_3px_10px_rgb(0,0,0,0.2)]">
{data.Spec[7].title}
</div>
<div className="bg-white py-32p px-[24px] rounded-[8px] text-center shadow-[0_3px_10px_rgb(0,0,0,0.2)]">
{data.Spec[8].title}
</div>
</div>
</div> </div>
</section>
</Wrapper>
<Wrapper padding={' py-[48px] mb-32p'}>
<h4 className='font-semibold font-secondary text-[#9B32CE] text-subtitle-48 text-center w-full'>How We Help Them?</h4>
</Wrapper>
<Wrapper padding={' py-90p'}>
<section>
<div className="flex flex-col justify-center items-start w-full max-w-custom m-auto px-8 xl:px-0 mb-32p">
<div className="flex flex-col gap-[72px] w-full max-w-[950px] mx-auto">
{_data.help.map((item, index) => (
<HelpParagraph
key={index}
title={item.title}
paragraph={item.paragraph}
/>
))}
) : null}
<div className="flex absolute w-full top-0 z-[-1]">
<div className="w-[624px] h-[624px] bg-indigo-500 opacity-25 rounded-full mx-auto blur-[100px]"></div>
</div>
</Wrapper>
</div>
{data ? (
<div className="md:mb-[200px]">
<div className="w-full relative mt-12 z-[-1]">
<div className="radial-gradient absolute top-0 left-0 right-0 bottom-0"></div>
<div className="max-w-custom mx-auto">
<img
src={api_url + data.OfficeImg.data.attributes.url}
alt={data.OfficeImgAlt}
></img>
</div> </div>
</div>
<div className="max-w-[600px] mx-[16px] md:mx-auto md:mt-[-320px] p-[24px] flex flex-col gap-[24px] z-20 bg-white rounded-[16px] shadow-[0_3px_10px_rgb(0,0,0,0.2)] md:shadow-none">
<div className="flex flex-col gap-[8px]">
<h6 className="n-h3-heading text-dark-gray font-bold">
{data.Download.title}
</h6>
<p className="n-paragraph">{data.Download.paragraph}</p>
</div> </div>
</section>
</Wrapper>
<Wrapper padding={' py-90p'} bg>
<h4 className='font-semibold font-secondary text-[#9B32CE] text-subtitle-48 text-center w-full py-32p'>What Our Customers Say?</h4>
<Testimonials noTitle />
</Wrapper>
<Wrapper padding={' py-[48px] mb-32p'}>
<h4 className='font-semibold font-secondary text-[#9B32CE] text-subtitle-48 text-center w-full py-32p'>Success</h4>
<p className='max-w-[1000px] mx-auto text-center w-full'>For us, the definition of success is a multifaceted subject. In short, we don’t declare a victory unless:</p>
<ul className='mx-[72px] lg:mx-[250px]'>
<li className='my-32p list-disc'>Deliverables are <b className='text-[#9B32CE]'>on time and within budget</b></li>
<li className='my-32p list-disc'>Deliverables are <b className='text-[#9B32CE]'>what the client needs</b>. We produce meaningful and positive contributions, we do not want to tick the checkboxes just so that we can call it done.</li>
<li className='my-32p list-disc'>Our resources involved with the client <b className='text-[#9B32CE]'>have gained knowledge in the process</b>, they understand the client’s business, what they’ve created and most importantly - why it was created</li>
<li className='my-32p list-disc'>Our clients can <b className='text-[#9B32CE]'>demonstratively measure the improvements</b> in stability, volume, earnings, their client/user satisfaction…as a result of our contribimport useAnalytics from './../hooks/useAnalytics';
utions. </li>

</ul>
</Wrapper>
<Wrapper padding={' py-32p'}>
<div className='flex flex-col md:flex gap-[32px] w-fit mx-auto'>
<CustomLink href={_data.downloadFilePath} downloadFile context={'Company Overview'}>
<p>Company Overview</p>
<DownalodIcon/>
</CustomLink>
</div>
</Wrapper>
<Wrapper padding={' py-90p'}>
<ActionCard
title="Let's Work Together!"
text="We’d be happy to try and find a way to contribute to your business."
btn2="Portfolio"
btn1="Contact Us"
link2={'/portfolio'}
link1={'/contact'}
/>
</Wrapper>
<CustomLink
href={download.downloadFilePath}
downloadFile={download.downloadFileName}
context={'Company Overview'}
>
<p>{data.Download.button}</p>
</CustomLink>
</div>
</div>
) : null}
{data ? (
<Wrapper padding={' py-90p'}>
<ActionCard
title={data.WorkTogether.title}
text={data.WorkTogether.paragraph}
btn2={data.WorkTogether.ButtonSecondary}
btn1={data.WorkTogether.ButtonPrimary}
link2={'/portfolio'}
link1={'/contact'}
/>
</Wrapper>
) : null}
</div>
)

}
</div>
</PageLayout>
);
}
};


export default WorkWithUs
export default WorkWithUs;

+ 2
- 2
frontend/src/styles/buttons.css Целия файл

} }


.btn-primary { .btn-primary {
@apply px-64p py-20p text-center
@apply px-32p py-20p sm:px-64p text-center
text-btn uppercase font-semibold rounded-16 border-transparent cursor-pointer bg-gradient-to-r from-dg-secondary to-dg-primary-900 transition-all hover:bg-gradient-to-r hover:to-dg-secondary hover:from-dg-primary-900 hover:transition-all text-white; text-btn uppercase font-semibold rounded-16 border-transparent cursor-pointer bg-gradient-to-r from-dg-secondary to-dg-primary-900 transition-all hover:bg-gradient-to-r hover:to-dg-secondary hover:from-dg-primary-900 hover:transition-all text-white;
} }
.btn-secondary { .btn-secondary {
@apply px-64p py-20p text-center
@apply px-32p py-20p sm:px-64p text-center
text-btn uppercase font-semibold rounded-16 cursor-pointer border-2 border-dg-primary-400 transition-all hover:transition-all text-dg-primary-900; text-btn uppercase font-semibold rounded-16 cursor-pointer border-2 border-dg-primary-400 transition-all hover:transition-all text-dg-primary-900;
} }
.contact-us-link { .contact-us-link {

+ 17
- 1
frontend/src/styles/text.css Целия файл



@layer components { @layer components {
.heading { .heading {
@apply font-primary text-dark-gray dark:text-white text-head-mobile md:text-head;
@apply font-secondary font-bold text-dark-gray dark:text-white text-n-head-mobile md:text-n-head;
} }


.subheading { .subheading {
.title-italic { .title-italic {
@apply text-italic-title text-dg-primary-400 font-semibold italic my-8p capitalize; @apply text-italic-title text-dg-primary-400 font-semibold italic my-8p capitalize;
} }

.n-heading {
@apply font-secondary font-bold text-dark-gray dark:text-white text-n-head-mobile md:text-n-head;
}
.n-subheading{
@apply text-n-subhead-mobile md:text-n-subhead font-secondary uppercase text-dg-secondary font-semibold;
}
.n-h3-heading{
@apply text-n-h3-heading-mobile md:text-n-h3-heading font-secondary text-dg-primary-900 font-bold;
}
.n-paragraph {
@apply text-n-paragraph-mobile md:text-n-paragraph font-secondary text-dark-gray font-normal
}
.n-paragraph-title {
@apply text-n-paragraph-title-mobile md:text-n-paragraph-title font-secondary text-dark-gray font-semibold
}
} }


.no-wrap { .no-wrap {

+ 13
- 0
frontend/src/utils/strapiApiBuilder.js Целия файл

const api_url = process.env.REACT_APP_API_URL;

export const strapiApiBuilder = (page, stringArray) => {
const api = `${api_url}/api/${page}`;
let query = '';
stringArray.map((field, index) => {
if (index === 0) query += `?populate[${index}]=${field}`;
else {
query += `&populate[${index}]=${field}`;
}
});
return api + query;
};

+ 95
- 25
frontend/tailwind.config.js Целия файл

darkMode: 'class', darkMode: 'class',
theme: { theme: {
fontFamily: { fontFamily: {
'primary' : ['"Abril Fatface"','serif'],
'secondary' : ['"Poppins"', 'sans-serif'],
primary: ['"Abril Fatface"', 'serif'],
secondary: ['"Poppins"', 'sans-serif'],
}, },
fontSize: { fontSize: {
'head' : ['56px', { 'head' : ['56px', {
'subtitle-48' : ['48px', { 'subtitle-48' : ['48px', {
letterSpacing: '0px', letterSpacing: '0px',
lineHeight: 'normal' lineHeight: 'normal'
}]
}],

//
'n-head' : ['54.00px', {
letterSpacing: '-0.6%',
lineHeight: '125%',
}],
'n-subhead' : ['16px', {
letterSpacing: '1.5px',
lineHeight: '24px',
}],
'n-head-mobile' : ['24px', {
letterSpacing: '-0.6%',
lineHeight: '32px',
}],
'n-subhead-mobile' : ['10.5px', {
letterSpacing: '1.5px',
lineHeight: '28px',
}],
'n-paragraph' : ['16px', {
letterSpacing: '0%',
lineHeight: '28px',
}],
'n-paragraph-mobile' : ['14px', {
letterSpacing: '0%',
lineHeight: '24px',
}],
'n-h3-heading' : ['24px', {
letterSpacing: '-0.6%',
lineHeight: '32px',
}],
'n-h3-heading-mobile' : ['18.66px', {
letterSpacing: '0%',
lineHeight: '24px',
}],
'n-paragraph-title-mobile' : ['14px', {
letterSpacing: '0%',
lineHeight: '24px',
}],
'n-paragraph-title' : ['18px', {
letterSpacing: '0%',
lineHeight: 'normal',
}],
'banner-mobile': [
'18.66px',
{
letterSpacing: '0px',
lineHeight: '24px',
},
],
'banner-p': [
'14px',
{
letterSpacing: '0px',
lineHeight: '21px',
},
],
'banner-p-mobile': [
'12px',
{
letterSpacing: '0px',
lineHeight: '18px',
},
],



}, },
minHeight: { minHeight: {
'12': '3rem',
12: '3rem',
}, },
maxWidth: { maxWidth: {
'780p':'780px',
'wrapper': '1150px',
'custom': '1150px',
'dropzone': '110px',
'780p': '780px',
wrapper: '1150px',
custom: '1150px',
dropzone: '110px',
banner: '1118px',
banner_m: '309px',
}, },
transitionDuration: { transitionDuration: {
DEFAULT: '300ms', DEFAULT: '300ms',
'baby-blue': '#f0f3f9', 'baby-blue': '#f0f3f9',
'dg-primary': { 'dg-primary': {
50: '#f4e9f4', 50: '#f4e9f4',
75: '#fafafa',
100: '#e9d4e9', 100: '#e9d4e9',
200: '#debedd', 200: '#debedd',
300: '#d3a9d2', 300: '#d3a9d2',
black: '#000000', black: '#000000',
}, },
spacing: { spacing: {
'2p': "2px",
'4p':'4px',
'2p': '2px',
'4p': '4px',
'8p': '8px', '8p': '8px',
'12p':'12px',
'12p': '12px',
'15p': '15px',
'16p': '16px', '16p': '16px',
'20p':'20px',
'32p':'32px',
'48p':'48px',
'64p':'64px',
'72p':'72px',
'90p':'90px',
'140p':'140px',
'20p': '20px',
'32p': '32px',
'42p': '42px',
'48p': '48px',
'64p': '64px',
'72p': '72px',
'90p': '90px',
'140p': '140px',
'164p': '164px', '164p': '164px',
'200p': '200px', '200p': '200px',
'240p':'240px'


'240p': '240px',
}, },
borderRadius: { borderRadius: {
'8': '8px',
'16': '16px',
'32' : '32px'
}
8: '8px',
16: '16px',
32: '32px',
},
boxShadow: {
custom: '0 0px 9px 9px rgba(0, 0, 0, 0.09)',
},
}, },
}, },
plugins: [ plugins: [

+ 118
- 10
frontend/yarn.lock Целия файл

dependencies: dependencies:
"@types/node" "*" "@types/node" "*"


"@types/cookie@^0.3.3":
"integrity" "sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow=="
"resolved" "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz"
"version" "0.3.3"

"@types/debug@^4.0.0": "@types/debug@^4.0.0":
"integrity" "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==" "integrity" "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg=="
"resolved" "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz" "resolved" "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz"
dependencies: dependencies:
"@types/unist" "*" "@types/unist" "*"


"@types/hoist-non-react-statics@^3.0.1":
"integrity" "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA=="
"resolved" "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz"
"version" "3.3.1"
dependencies:
"@types/react" "*"
"hoist-non-react-statics" "^3.3.0"

"@types/html-minifier-terser@^6.0.0": "@types/html-minifier-terser@^6.0.0":
"integrity" "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" "integrity" "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg=="
"resolved" "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz" "resolved" "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz"
"resolved" "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz" "resolved" "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz"
"version" "1.2.4" "version" "1.2.4"


"@types/react@>=16":
"@types/react@*", "@types/react@>=16":
"integrity" "sha512-7QUCOxvFgnD5Jk8ZKlUAhVcRj7GuJRjnjjiY/IUBWKgOlnvDvTMLD4RTF7NPyVmbRhNrbomZiOepg7M/2Kj1mA==" "integrity" "sha512-7QUCOxvFgnD5Jk8ZKlUAhVcRj7GuJRjnjjiY/IUBWKgOlnvDvTMLD4RTF7NPyVmbRhNrbomZiOepg7M/2Kj1mA=="
"resolved" "https://registry.npmjs.org/@types/react/-/react-18.0.21.tgz" "resolved" "https://registry.npmjs.org/@types/react/-/react-18.0.21.tgz"
"version" "18.0.21" "version" "18.0.21"
dependencies: dependencies:
"follow-redirects" "^1.14.8" "follow-redirects" "^1.14.8"


"axios@^0.27.2":
"integrity" "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ=="
"resolved" "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz"
"version" "0.27.2"
dependencies:
"follow-redirects" "^1.14.9"
"form-data" "^4.0.0"

"axobject-query@^2.2.0": "axobject-query@^2.2.0":
"integrity" "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==" "integrity" "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA=="
"resolved" "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz" "resolved" "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz"
"resolved" "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" "resolved" "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
"version" "1.0.2" "version" "1.0.2"


"base-64@^1.0.0":
"integrity" "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg=="
"resolved" "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz"
"version" "1.0.0"

"batch@0.6.1": "batch@0.6.1":
"integrity" "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=" "integrity" "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY="
"resolved" "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz" "resolved" "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz"
"resolved" "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" "resolved" "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz"
"version" "1.0.6" "version" "1.0.6"


"cookie@0.4.1":
"cookie@^0.4.0", "cookie@0.4.1":
"integrity" "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" "integrity" "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA=="
"resolved" "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz" "resolved" "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz"
"version" "0.4.1" "version" "0.4.1"
"resolved" "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz" "resolved" "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz"
"version" "3.2.4" "version" "3.2.4"


"follow-redirects@^1.0.0", "follow-redirects@^1.14.8":
"integrity" "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA=="
"resolved" "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz"
"version" "1.14.8"
"follow-redirects@^1.0.0", "follow-redirects@^1.14.8", "follow-redirects@^1.14.9":
"integrity" "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
"resolved" "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz"
"version" "1.15.2"


"fork-ts-checker-webpack-plugin@^6.5.0": "fork-ts-checker-webpack-plugin@^6.5.0":
"integrity" "sha512-cS178Y+xxtIjEUorcHddKS7yCMlrDPV31mt47blKKRfMd70Kxu5xruAFE2o9sDY6wVC5deuob/u/alD04YYHnw==" "integrity" "sha512-cS178Y+xxtIjEUorcHddKS7yCMlrDPV31mt47blKKRfMd70Kxu5xruAFE2o9sDY6wVC5deuob/u/alD04YYHnw=="
"combined-stream" "^1.0.8" "combined-stream" "^1.0.8"
"mime-types" "^2.1.12" "mime-types" "^2.1.12"


"form-data@^4.0.0":
"integrity" "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww=="
"resolved" "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz"
"version" "4.0.0"
dependencies:
"asynckit" "^0.4.0"
"combined-stream" "^1.0.8"
"mime-types" "^2.1.12"

"formik@^2.2.9": "formik@^2.2.9":
"integrity" "sha512-LQLcISMmf1r5at4/gyJigGn0gOwFbeEAlji+N9InZF6LIMXnFNkO42sCI8Jt84YZggpD4cPWObAZaxpEFtSzNA==" "integrity" "sha512-LQLcISMmf1r5at4/gyJigGn0gOwFbeEAlji+N9InZF6LIMXnFNkO42sCI8Jt84YZggpD4cPWObAZaxpEFtSzNA=="
"resolved" "https://registry.npmjs.org/formik/-/formik-2.2.9.tgz" "resolved" "https://registry.npmjs.org/formik/-/formik-2.2.9.tgz"
"resolved" "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz" "resolved" "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz"
"version" "2.2.0" "version" "2.2.0"


"invariant@2.2.4":
"invariant@^2.2.4", "invariant@2.2.4":
"integrity" "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==" "integrity" "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA=="
"resolved" "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz" "resolved" "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz"
"version" "2.2.4" "version" "2.2.4"
dependencies: dependencies:
"sourcemap-codec" "^1.4.4" "sourcemap-codec" "^1.4.4"


"mailgun.js@^8.0.6":
"integrity" "sha512-b+c7QO1T4oFsudEcRB2H7oZKth8ZDeYRW4xjW12QQVNYDSJCVxqSQfps6ofcH8fqcCMJdzc76HVNGdnUZgBPCw=="
"resolved" "https://registry.npmjs.org/mailgun.js/-/mailgun.js-8.0.6.tgz"
"version" "8.0.6"
dependencies:
"axios" "^0.27.2"
"base-64" "^1.0.0"
"url-join" "^4.0.1"

"make-dir@^3.0.0", "make-dir@^3.0.2", "make-dir@^3.1.0": "make-dir@^3.0.0", "make-dir@^3.0.2", "make-dir@^3.1.0":
"integrity" "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==" "integrity" "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="
"resolved" "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz" "resolved" "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz"
"kleur" "^3.0.3" "kleur" "^3.0.3"
"sisteransi" "^1.0.5" "sisteransi" "^1.0.5"


"prop-types@^15.0.0", "prop-types@^15.5.10", "prop-types@^15.7.2", "prop-types@^15.8.1":
"prop-types@^15.0.0", "prop-types@^15.5.0", "prop-types@^15.5.10", "prop-types@^15.6.0", "prop-types@^15.7.2", "prop-types@^15.8.1":
"integrity" "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==" "integrity" "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="
"resolved" "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" "resolved" "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz"
"version" "15.8.1" "version" "15.8.1"
"regenerator-runtime" "^0.13.9" "regenerator-runtime" "^0.13.9"
"whatwg-fetch" "^3.6.2" "whatwg-fetch" "^3.6.2"


"react-async-script@^1.1.1":
"integrity" "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q=="
"resolved" "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz"
"version" "1.2.0"
dependencies:
"hoist-non-react-statics" "^3.3.0"
"prop-types" "^15.5.0"

"react-cookie@^4.1.1":
"integrity" "sha512-ffn7Y7G4bXiFbnE+dKhHhbP+b8I34mH9jqnm8Llhj89zF4nPxPutxHT1suUqMeCEhLDBI7InYwf1tpaSoK5w8A=="
"resolved" "https://registry.npmjs.org/react-cookie/-/react-cookie-4.1.1.tgz"
"version" "4.1.1"
dependencies:
"@types/hoist-non-react-statics" "^3.0.1"
"hoist-non-react-statics" "^3.0.0"
"universal-cookie" "^4.0.0"

"react-dev-utils@^12.0.0": "react-dev-utils@^12.0.0":
"integrity" "sha512-xBQkitdxozPxt1YZ9O1097EJiVpwHr9FoAuEVURCKV0Av8NBERovJauzP7bo1ThvuhZ4shsQ1AJiu4vQpoT1AQ==" "integrity" "sha512-xBQkitdxozPxt1YZ9O1097EJiVpwHr9FoAuEVURCKV0Av8NBERovJauzP7bo1ThvuhZ4shsQ1AJiu4vQpoT1AQ=="
"resolved" "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.0.tgz" "resolved" "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.0.tgz"
"strip-ansi" "^6.0.1" "strip-ansi" "^6.0.1"
"text-table" "^0.2.0" "text-table" "^0.2.0"


"react-dom@*", "react-dom@^16 || ^17 || ^18", "react-dom@^16.8 || ^17 || ^18", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom@^17.0.2", "react-dom@>= 16.8.0", "react-dom@>=16.8", "react-dom@>=16.8 || ^17.0.0 || ^18.0.0":
"react-dom@*", "react-dom@^16 || ^17 || ^18", "react-dom@^16.6.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8 || ^17 || ^18", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom@^17.0.2", "react-dom@>= 16.8.0", "react-dom@>=16.8", "react-dom@>=16.8 || ^17.0.0 || ^18.0.0":
"integrity" "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==" "integrity" "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA=="
"resolved" "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz" "resolved" "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz"
"version" "17.0.2" "version" "17.0.2"
"resolved" "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz" "resolved" "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz"
"version" "2.0.4" "version" "2.0.4"


"react-fast-compare@^3.2.0":
"integrity" "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA=="
"resolved" "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz"
"version" "3.2.0"

"react-ga@^3.3.1":
"integrity" "sha512-4Vc0W5EvXAXUN/wWyxvsAKDLLgtJ3oLmhYYssx+YzphJpejtOst6cbIHCIyF50Fdxuf5DDKqRYny24yJ2y7GFQ=="
"resolved" "https://registry.npmjs.org/react-ga/-/react-ga-3.3.1.tgz"
"version" "3.3.1"

"react-ga4@^1.4.1":
"integrity" "sha512-ioBMEIxd4ePw4YtaloTUgqhQGqz5ebDdC4slEpLgy2sLx1LuZBC9iYCwDymTXzcntw6K1dHX183ulP32nNdG7w=="
"resolved" "https://registry.npmjs.org/react-ga4/-/react-ga4-1.4.1.tgz"
"version" "1.4.1"

"react-google-recaptcha@^2.1.0":
"integrity" "sha512-K9jr7e0CWFigi8KxC3WPvNqZZ47df2RrMAta6KmRoE4RUi7Ys6NmNjytpXpg4HI/svmQJLKR+PncEPaNJ98DqQ=="
"resolved" "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-2.1.0.tgz"
"version" "2.1.0"
dependencies:
"prop-types" "^15.5.0"
"react-async-script" "^1.1.1"

"react-helmet-async@^1.3.0":
"integrity" "sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg=="
"resolved" "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.3.0.tgz"
"version" "1.3.0"
dependencies:
"@babel/runtime" "^7.12.5"
"invariant" "^2.2.4"
"prop-types" "^15.7.2"
"react-fast-compare" "^3.2.0"
"shallowequal" "^1.1.0"

"react-is@^16.13.1", "react-is@^16.7.0", "react-is@>= 16.8.0": "react-is@^16.13.1", "react-is@^16.7.0", "react-is@>= 16.8.0":
"integrity" "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" "integrity" "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
"resolved" "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" "resolved" "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
optionalDependencies: optionalDependencies:
"fsevents" "^2.3.2" "fsevents" "^2.3.2"


"react@*", "react@^16 || ^17 || ^18", "react@^16.8 || ^17 || ^18", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^17.0.2", "react@>= 16", "react@>= 16.8", "react@>= 16.8.0", "react@>=15", "react@>=16", "react@>=16.8", "react@>=16.8 || ^17.0.0 || ^18.0.0", "react@>=16.8.0", "react@17.0.2":
"react@*", "react@^15.6.2 || ^16.0 || ^17 || ^18", "react@^16 || ^17 || ^18", "react@^16.6.0 || ^17.0.0 || ^18.0.0", "react@^16.8 || ^17 || ^18", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^17.0.2", "react@>= 16", "react@>= 16.3.0", "react@>= 16.8", "react@>= 16.8.0", "react@>=15", "react@>=16", "react@>=16.4.1", "react@>=16.8", "react@>=16.8 || ^17.0.0 || ^18.0.0", "react@>=16.8.0", "react@17.0.2":
"integrity" "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==" "integrity" "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA=="
"resolved" "https://registry.npmjs.org/react/-/react-17.0.2.tgz" "resolved" "https://registry.npmjs.org/react/-/react-17.0.2.tgz"
"version" "17.0.2" "version" "17.0.2"
"unist-util-is" "^5.0.0" "unist-util-is" "^5.0.0"
"unist-util-visit-parents" "^5.0.0" "unist-util-visit-parents" "^5.0.0"


"universal-cookie@^4.0.0":
"integrity" "sha512-lbRVHoOMtItjWbM7TwDLdl8wug7izB0tq3/YVKhT/ahB4VDvWMyvnADfnJI8y6fSvsjh51Ix7lTGC6Tn4rMPhw=="
"resolved" "https://registry.npmjs.org/universal-cookie/-/universal-cookie-4.0.4.tgz"
"version" "4.0.4"
dependencies:
"@types/cookie" "^0.3.3"
"cookie" "^0.4.0"

"universalify@^0.1.2": "universalify@^0.1.2":
"integrity" "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" "integrity" "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
"resolved" "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz" "resolved" "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz"
dependencies: dependencies:
"punycode" "^2.1.0" "punycode" "^2.1.0"


"url-join@^4.0.1":
"integrity" "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="
"resolved" "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz"
"version" "4.0.1"

"util-deprecate@^1.0.1", "util-deprecate@^1.0.2", "util-deprecate@~1.0.1": "util-deprecate@^1.0.1", "util-deprecate@^1.0.2", "util-deprecate@~1.0.1":
"integrity" "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" "integrity" "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
"resolved" "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" "resolved" "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"

Loading…
Отказ
Запис