Pavle Golubovic 3 лет назад
Родитель
Сommit
0456347f0d
63 измененных файлов: 2778 добавлений и 1120 удалений
  1. 1
    1
      frontend/.env
  2. 70
    2
      frontend/package-lock.json
  3. 5
    1
      frontend/package.json
  4. 17
    11
      frontend/src/App.js
  5. Двоичные данные
      frontend/src/assets/Diligent Pool Party - 10.09.mp4
  6. 3
    0
      frontend/src/assets/chevron.svg
  7. 4
    0
      frontend/src/assets/icons/volume.svg
  8. Двоичные данные
      frontend/src/assets/images/Careers/events.png
  9. Двоичные данные
      frontend/src/assets/images/Careers/img1.png
  10. Двоичные данные
      frontend/src/assets/images/Careers/img2.png
  11. Двоичные данные
      frontend/src/assets/images/Careers/img3.png
  12. Двоичные данные
      frontend/src/assets/images/Careers/img4.png
  13. Двоичные данные
      frontend/src/assets/nick.jpg
  14. 0
    1
      frontend/src/components/BlogSection.jsx
  15. 1
    1
      frontend/src/components/CareerCardsTemplates/CardCareers2.jsx
  16. 6
    12
      frontend/src/components/CareerCardsTemplates/ExpandedCard.jsx
  17. 132
    0
      frontend/src/components/HRProcess.jsx
  18. 39
    27
      frontend/src/components/Landing.jsx
  19. 2
    2
      frontend/src/components/Map.jsx
  20. 0
    4
      frontend/src/components/PortfolioCard.jsx
  21. 3
    3
      frontend/src/components/PortfolioSection.jsx
  22. 42
    45
      frontend/src/components/ProcessSection.jsx
  23. 2
    2
      frontend/src/components/ProcessSlider.jsx
  24. 0
    1
      frontend/src/components/ServicesHome.jsx
  25. 3
    3
      frontend/src/components/TechStack.jsx
  26. 22
    0
      frontend/src/components/Testimonials.jsx
  27. 18
    18
      frontend/src/components/WhySection.jsx
  28. 3
    1
      frontend/src/components/WhyUsCard.jsx
  29. 153
    0
      frontend/src/components/WorkClientForm.jsx
  30. 9
    11
      frontend/src/components/root/CustomLink.jsx
  31. 1
    1
      frontend/src/components/shared/CardValues.jsx
  32. 15
    4
      frontend/src/components/shared/ClientForm.jsx
  33. 18
    14
      frontend/src/components/shared/Contact.jsx
  34. 3
    2
      frontend/src/components/shared/HashPositions.jsx
  35. 12
    4
      frontend/src/components/shared/JobForm.jsx
  36. 110
    27
      frontend/src/components/shared/Navigation.jsx
  37. 179
    0
      frontend/src/components/shared/NavigationNew.jsx
  38. 4
    2
      frontend/src/components/shared/PageHeading.jsx
  39. 3
    3
      frontend/src/components/shared/PageTitle.jsx
  40. 1
    1
      frontend/src/components/shared/ProcessCard.jsx
  41. 6
    4
      frontend/src/components/shared/ProcessFacelessSlider.jsx
  42. 2
    1
      frontend/src/components/shared/ReactHelmet.jsx
  43. 58
    0
      frontend/src/components/shared/VideoComponent.jsx
  44. 1
    1
      frontend/src/context/index.js
  45. 60
    37
      frontend/src/hooks/useDataApi.js
  46. 21
    0
      frontend/src/hooks/useHoverOutside.js
  47. 5
    0
      frontend/src/index.css
  48. 5
    1
      frontend/src/index.js
  49. 1
    1
      frontend/src/layout/Wrapper.jsx
  50. 233
    374
      frontend/src/pages/About.jsx
  51. 214
    199
      frontend/src/pages/Careers.jsx
  52. 32
    8
      frontend/src/pages/ContactPage.jsx
  53. 247
    0
      frontend/src/pages/DiligentLife.jsx
  54. 307
    0
      frontend/src/pages/DiligentMinds.jsx
  55. 384
    0
      frontend/src/pages/EventsTimeline.jsx
  56. 90
    74
      frontend/src/pages/Home.jsx
  57. 88
    160
      frontend/src/pages/ProcessPage.jsx
  58. 79
    50
      frontend/src/pages/WorkWithUs.jsx
  59. 27
    1
      frontend/src/routes.js
  60. 5
    0
      frontend/src/styles/cards.css
  61. 1
    1
      frontend/src/styles/text.css
  62. 2
    2
      frontend/tailwind.config.js
  63. 29
    2
      frontend/yarn.lock

+ 1
- 1
frontend/.env Просмотреть файл

REACT_APP_JOB_TEMPLATE_ID = template_bfuv1sb REACT_APP_JOB_TEMPLATE_ID = template_bfuv1sb
REACT_APP_CLIENT_TEMPLATE_ID = template_bd6fjli REACT_APP_CLIENT_TEMPLATE_ID = template_bd6fjli
REACT_APP_USER_ID = 27spvSZ2Lsf2j8RKw REACT_APP_USER_ID = 27spvSZ2Lsf2j8RKw
REACT_APP_API_URL = "https://diligentwebsiteapistart.azurewebsites.net"
REACT_APP_API_URL = "https://website-api-dev.dilig.net"
//http://localhost:1337 //http://localhost:1337
MAILCHIMP_FORM_URL = http://eepurl.com/iaRrv1 MAILCHIMP_FORM_URL = http://eepurl.com/iaRrv1
GOOGLE_TRACKING_ID = "G-PTZC3WLTZ1" GOOGLE_TRACKING_ID = "G-PTZC3WLTZ1"

+ 70
- 2
frontend/package-lock.json Просмотреть файл

{ {
"name": "frontend", "name": "frontend",
"version": "1.1.15",
"version": "1.1.18",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "frontend", "name": "frontend",
"version": "1.1.15",
"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",
"form-data": "^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",
"gsap": "^3.11.4",
"js-file-download": "^0.4.12",
"mailgun.js": "^8.0.6", "mailgun.js": "^8.0.6",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"react": "^17.0.2", "react": "^17.0.2",
"react-ga4": "^1.4.1", "react-ga4": "^1.4.1",
"react-google-recaptcha": "^2.1.0", "react-google-recaptcha": "^2.1.0",
"react-helmet-async": "^1.3.0", "react-helmet-async": "^1.3.0",
"react-intersection-observer": "^9.4.1",
"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",
"react-scripts": "5.0.0", "react-scripts": "5.0.0",
"react-useanimations": "^2.10.0",
"styled-components": "^5.3.5", "styled-components": "^5.3.5",
"tailwind.macro": "^0.5.10", "tailwind.macro": "^0.5.10",
"web-vitals": "^2.1.3", "web-vitals": "^2.1.3",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
"integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ=="
}, },
"node_modules/gsap": {
"version": "3.11.4",
"resolved": "https://registry.npmjs.org/gsap/-/gsap-3.11.4.tgz",
"integrity": "sha512-McHhEguHyExMMnjqKA8G+7TvxmlKQGMbjgwAilnFe1e4id7V/tFveRQ2YMZhTYu0oxHGWvbPltdVYQOu3z1SCA=="
},
"node_modules/gzip-size": { "node_modules/gzip-size": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz",
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/js-file-download": {
"version": "0.4.12",
"resolved": "https://registry.npmjs.org/js-file-download/-/js-file-download-0.4.12.tgz",
"integrity": "sha512-rML+NkoD08p5Dllpjo0ffy4jRHeY6Zsapvr/W86N7E0yuzAO6qa5X9+xog6zQNlH102J7IXljNY2FtS6Lj3ucg=="
},
"node_modules/js-tokens": { "node_modules/js-tokens": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"loose-envify": "cli.js" "loose-envify": "cli.js"
} }
}, },
"node_modules/lottie-web": {
"version": "5.10.2",
"resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.10.2.tgz",
"integrity": "sha512-d0PFIGiwuMsJYaF4uPo+qG8dEorlI+xFI2zrrFtE1bGO4WoLIz+NjremxEq1swpR7juR10aeOtmNh3d6G3ub0A=="
},
"node_modules/lower-case": { "node_modules/lower-case": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz",
"integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA=="
}, },
"node_modules/react-intersection-observer": {
"version": "9.4.1",
"resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.4.1.tgz",
"integrity": "sha512-IXpIsPe6BleFOEHKzKh5UjwRUaz/JYS0lT/HPsupWEQou2hDqjhLMStc5zyE3eQVT4Fk3FufM8Fw33qW1uyeiw==",
"peerDependencies": {
"react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
}
},
"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",
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/react-useanimations": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/react-useanimations/-/react-useanimations-2.10.0.tgz",
"integrity": "sha512-MzGNv8vkvb6qEvMBCj+O6nUloUHSJRubMAH3uE7J4M+pjt5ud5xDaXBrQgv5GbvBg29XzviKWHTfvvkofDEu+Q==",
"dependencies": {
"lottie-web": "^5.5.7"
},
"peerDependencies": {
"react": ">=16",
"react-dom": ">=16"
}
},
"node_modules/readable-stream": { "node_modules/readable-stream": {
"version": "3.6.0", "version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
"integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ=="
}, },
"gsap": {
"version": "3.11.4",
"resolved": "https://registry.npmjs.org/gsap/-/gsap-3.11.4.tgz",
"integrity": "sha512-McHhEguHyExMMnjqKA8G+7TvxmlKQGMbjgwAilnFe1e4id7V/tFveRQ2YMZhTYu0oxHGWvbPltdVYQOu3z1SCA=="
},
"gzip-size": { "gzip-size": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz",
} }
} }
}, },
"js-file-download": {
"version": "0.4.12",
"resolved": "https://registry.npmjs.org/js-file-download/-/js-file-download-0.4.12.tgz",
"integrity": "sha512-rML+NkoD08p5Dllpjo0ffy4jRHeY6Zsapvr/W86N7E0yuzAO6qa5X9+xog6zQNlH102J7IXljNY2FtS6Lj3ucg=="
},
"js-tokens": { "js-tokens": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"js-tokens": "^3.0.0 || ^4.0.0" "js-tokens": "^3.0.0 || ^4.0.0"
} }
}, },
"lottie-web": {
"version": "5.10.2",
"resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.10.2.tgz",
"integrity": "sha512-d0PFIGiwuMsJYaF4uPo+qG8dEorlI+xFI2zrrFtE1bGO4WoLIz+NjremxEq1swpR7juR10aeOtmNh3d6G3ub0A=="
},
"lower-case": { "lower-case": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
} }
} }
}, },
"react-intersection-observer": {
"version": "9.4.1",
"resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.4.1.tgz",
"integrity": "sha512-IXpIsPe6BleFOEHKzKh5UjwRUaz/JYS0lT/HPsupWEQou2hDqjhLMStc5zyE3eQVT4Fk3FufM8Fw33qW1uyeiw==",
"requires": {}
},
"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",
} }
} }
}, },
"react-useanimations": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/react-useanimations/-/react-useanimations-2.10.0.tgz",
"integrity": "sha512-MzGNv8vkvb6qEvMBCj+O6nUloUHSJRubMAH3uE7J4M+pjt5ud5xDaXBrQgv5GbvBg29XzviKWHTfvvkofDEu+Q==",
"requires": {
"lottie-web": "^5.5.7"
}
},
"readable-stream": { "readable-stream": {
"version": "3.6.0", "version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",

+ 5
- 1
frontend/package.json Просмотреть файл

{ {
"name": "frontend", "name": "frontend",
"version": "1.1.18",
"version": "1.2.1",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@faceless-ui/slider": "^1.1.14", "@faceless-ui/slider": "^1.1.14",
"form-data": "^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",
"gsap": "^3.11.4",
"js-file-download": "^0.4.12",
"mailgun.js": "^8.0.6", "mailgun.js": "^8.0.6",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"react": "^17.0.2", "react": "^17.0.2",
"react-ga4": "^1.4.1", "react-ga4": "^1.4.1",
"react-google-recaptcha": "^2.1.0", "react-google-recaptcha": "^2.1.0",
"react-helmet-async": "^1.3.0", "react-helmet-async": "^1.3.0",
"react-intersection-observer": "^9.4.1",
"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",
"react-scripts": "5.0.0", "react-scripts": "5.0.0",
"react-useanimations": "^2.10.0",
"styled-components": "^5.3.5", "styled-components": "^5.3.5",
"tailwind.macro": "^0.5.10", "tailwind.macro": "^0.5.10",
"web-vitals": "^2.1.3", "web-vitals": "^2.1.3",

+ 17
- 11
frontend/src/App.js Просмотреть файл

const Portfolio = lazy(() => import('./pages/Portfolio')); const Portfolio = lazy(() => import('./pages/Portfolio'));
const Services = lazy(() => import('./pages/Services')); const Services = lazy(() => import('./pages/Services'));
const Careers = lazy(() => import('./pages/Careers')); const Careers = lazy(() => import('./pages/Careers'));
const DiligentLife = lazy(() => import('./pages/DiligentLife'));
const DiligentMinds = lazy(() => import('./pages/DiligentMinds'));
const EventsTimeline = lazy(() => import('./pages/EventsTimeline'));
const About = lazy(() => import('./pages/About')); const About = lazy(() => import('./pages/About'));
const BlogPost = lazy(() => import('./components/BlogPost')); const BlogPost = lazy(() => import('./components/BlogPost'));
const ProcessPage = lazy(() => import('./pages/ProcessPage')); const ProcessPage = lazy(() => import('./pages/ProcessPage'));
const CaseStudyStrata = lazy(() => import('./pages/CaseStudyStrata')); const CaseStudyStrata = lazy(() => import('./pages/CaseStudyStrata'));
const PrivacyPolicy = lazy(() => import('./pages/PrivacyPolicy')); const PrivacyPolicy = lazy(() => import('./pages/PrivacyPolicy'));
const WorkWithUs = lazy(() => import('./pages/WorkWithUs')); const WorkWithUs = lazy(() => import('./pages/WorkWithUs'));
import NavigationNew from './components/shared/NavigationNew';


// Navigation Links // Navigation Links
const links = routes.filter(item => item.nav === true); const links = routes.filter(item => item.nav === true);
function scrollToView(event) { function scrollToView(event) {
event.preventDefault(); event.preventDefault();
if (forwardedRef) { if (forwardedRef) {
//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');
<Route exact path="/workwithus" element={<WorkWithUs />} /> <Route exact path="/workwithus" element={<WorkWithUs />} />
<Route exact path="/portfolio" element={<Portfolio />} /> <Route exact path="/portfolio" element={<Portfolio />} />
<Route exact path="/process" element={<ProcessPage />} /> <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="/careers" element={<Careers />}/>
<Route exact path="/diligentlife" element={<DiligentLife />}/>
<Route exact path="/diligentminds" element={<DiligentMinds />}/>
<Route exact path="/eventstimeline" element={<EventsTimeline />}/>
<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/Diligent Pool Party - 10.09.mp4 Просмотреть файл


+ 3
- 0
frontend/src/assets/chevron.svg Просмотреть файл

<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="-4 -4 32 32" stroke-width="1.5" stroke="currentColor" class="w-3 h-3">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
</svg>

+ 4
- 0
frontend/src/assets/icons/volume.svg Просмотреть файл

<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="24" height="24" fill="white"/>
<path d="M5.5 10V14C5.5 16 6.5 17 8.5 17H9.93C10.3 17 10.67 17.11 10.99 17.3L13.91 19.13C16.43 20.71 18.5 19.56 18.5 16.59V7.41003C18.5 4.43003 16.43 3.29003 13.91 4.87003L10.99 6.70003C10.67 6.89003 10.3 7.00003 9.93 7.00003H8.5C6.5 7.00003 5.5 8.00003 5.5 10Z" stroke="#292D32" stroke-width="1.5"/>
</svg>

Двоичные данные
frontend/src/assets/images/Careers/events.png Просмотреть файл


Двоичные данные
frontend/src/assets/images/Careers/img1.png Просмотреть файл


Двоичные данные
frontend/src/assets/images/Careers/img2.png Просмотреть файл


Двоичные данные
frontend/src/assets/images/Careers/img3.png Просмотреть файл


Двоичные данные
frontend/src/assets/images/Careers/img4.png Просмотреть файл


Двоичные данные
frontend/src/assets/nick.jpg Просмотреть файл


+ 0
- 1
frontend/src/components/BlogSection.jsx Просмотреть файл

axios axios
.get(`${api_url}/api/blogpage?populate[0]=post.image`) .get(`${api_url}/api/blogpage?populate[0]=post.image`)
.then(res => { .then(res => {
//console.log(res.data.data.attributes);
setCntBlog(res.data.data.attributes); setCntBlog(res.data.data.attributes);
setIsLoaded(true); setIsLoaded(true);
}) })

+ 1
- 1
frontend/src/components/CareerCardsTemplates/CardCareers2.jsx Просмотреть файл

{isComponentVisible ? {isComponentVisible ?
<ExpandedCard card={expandedCard} setExpanded={setIsComponentVisible} setExpandedCard={setExpandedCard}></ExpandedCard> <ExpandedCard card={expandedCard} setExpanded={setIsComponentVisible} setExpandedCard={setExpandedCard}></ExpandedCard>
: :
<div className='flex flex-col md:flex-row justify-center w-full gap-8'>
<div className='flex flex-col md:flex-row justify-center items-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} />

+ 6
- 12
frontend/src/components/CareerCardsTemplates/ExpandedCard.jsx Просмотреть файл

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


const {uiContext, setUiContext} = useContext(UIContext);
const handleNavigate = (tab, position) => {
linkTo('/contact', { tab: { tab}, position: { position } });
}


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


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


return ( return (
<a <a
href="/contact" href="/contact"
className="btn btn_primary mt-8 transition-all hover:transition-all" className="btn btn_primary mt-8 transition-all hover:transition-all"
onClick={()=> handleContext(card.id)}
onClick={handleNavigate(false, ".Net")}
> >
Apply Apply
</a> </a>
<a <a
href="/contact" href="/contact"
className="btn btn_primary mt-8 transition-all hover:transition-all" className="btn btn_primary mt-8 transition-all hover:transition-all"
onClick={()=> handleContext(card.id)}
onClick={handleNavigate(false, ".Net")}
> >
Apply Apply
</a> </a>

+ 132
- 0
frontend/src/components/HRProcess.jsx Просмотреть файл

import React, { useRef, useEffect } from 'react';
import { useScroll } from 'framer-motion';

const api_url = process.env.REACT_APP_API_URL;

const HRProcess = ({ data }) => {
//console.log(data);

const ref = useRef(null);
const { scrollYProgress } = useScroll({ container: ref });

useEffect(() => {
const imageArray = document.querySelectorAll('.image-switch');
//console.log(imageArray);
const switchImage = scrollYProgress.onChange(value => {
if (value <= 0.1) {
imageArray.forEach(el => el.classList.remove('active-image'));
imageArray[0].classList.add('active-image');
}
if (value > 0.1) {
imageArray.forEach(el => el.classList.remove('active-image'));
imageArray[1].classList.add('active-image');
}
if (value > 0.4) {
imageArray.forEach(el => el.classList.remove('active-image'));
imageArray[2].classList.add('active-image');
}
if (value > 0.6) {
imageArray.forEach(el => el.classList.remove('active-image'));
imageArray[3].classList.add('active-image');
}
if (value > 0.8) {
imageArray.forEach(el => el.classList.remove('active-image'));
imageArray[4].classList.add('active-image');
}
// switch (value) {
// case value > 0.2:
// console.log(1);
// //document.querySelectorAll('.image-switch');
// imageArray.forEach(el => el.classList.remove('active-image'));
// imageArray[1].classList.add('active-image');
// break;
// case value > 0.4:
// console.log(2);
// imageArray.forEach(el => el.classList.remove('active-image'));
// imageArray[2].classList.add('active-image');
// break;
// case value > 0.6:
// imageArray.forEach(el => el.classList.remove('active-image'));
// imageArray[3].classList.add('active-image');
// break;
// case value > 0.8:
// imageArray.forEach(el => el.classList.remove('active-image'));
// imageArray[4].classList.add('active-image');
// break;
// default:
// imageArray.forEach(el => el.classList.remove('active-image'));
// imageArray[0].classList.add('active-image');
// }

// if (value > 0.5)
// {
// document.querySelector('#img-one').classList.add('opacity-0');
// document.querySelector('#img-one').classList.remove('opacity-1');
// document.querySelector('#img-two').classList.remove('opacity-0');
// document.querySelector('#img-two').classList.add('opacity-1');
// }
// else{
// document.querySelector('#img-one').classList.remove('opacity-0');
// document.querySelector('#img-one').classList.add('opacity-1');
// document.querySelector('#img-two').classList.add('opacity-0');
// document.querySelector('#img-two').classList.remove('opacity-1');
// }
});

return () => {
switchImage();
};
});

return (
<div
ref={ref}
id="steps-container"
className="steps-container no-scrollbar flex flex-col items-center justify-start overflow-auto h-[75vh] pt-72p pl-3"
>
{/* Dynamic Image */}
{data.selection_process.steps.map((item, index) => (
<img
key={index}
src={api_url + item.media.data.attributes.url}
alt={item.media.data.attributes.alternativeText}
className={
'image-switch bg-fixed hidden sm:block opacity-0 absolute top-1/4 right-10 w-2/5 transition-all' +
(index == 0 ? ' active-image' : '')
}
/>
))}

<div className="local">
{data.selection_process.steps.map((item, index) => (
<>
{/* Section */}
<div
id={item.id}
className="relative flex flex-col sm:flex-row items-start justify-center sm:gap-16 min-h-fit max-h[100vh] mb-28 md:mb-56"
>
{/* Line */}
<hr className="bg-gray-400 w-full absolute -left-1/2 rotate-90" />

{/* Dot */}
<div className="z-10 p-[0.36rem] rounded-full bg-white border-solid border border-dg-primary-900 absolute -left-[0.63%] top-[1%]"></div>

<div className="sm:w-1/2 ml-8">
<h3 className="h3-heading">{item.heading}</h3>
<p className="text-sm text-dark-gray dark:text-white mt-4">
{item.paragraph}
</p>
{item.cto != null && (
<button className="btn-secondary mt-6 min-w-fit">{item.cto}</button>
)}
</div>
<div className="w-1/2"></div>
</div>
</>
))}
</div>
</div>
);
};

export default HRProcess;

+ 39
- 27
frontend/src/components/Landing.jsx Просмотреть файл

import React from 'react';
import React, { useEffect } from 'react';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import LandingSVGv2 from './shared/graphics/LandingSVG-v2'; import LandingSVGv2 from './shared/graphics/LandingSVG-v2';
import HiringWidget from './HiringWidget'; import HiringWidget from './HiringWidget';
import Wrapper from '../layout/Wrapper'; import Wrapper from '../layout/Wrapper';
import OpenDayBanner from './OpenDayBanner'; import OpenDayBanner from './OpenDayBanner';


const _data = {
cto: 'contact us',
};
const numbers = [
{
value: 90,
static: '+',
title: 'Employees',
},
{
value: '20',
static: '+',
title: 'Projects',
},
{
value: '100',
static: '%',
title: 'Client-Retention',
},
];
// const _data = {
// cto: 'contact us',
// };
// const number = [
// {
// value: 90,
// static: '+',
// title: 'Employees',
// },
// {
// value: '20',
// static: '+',
// title: 'Projects',
// },
// {
// value: '100',
// static: '%',
// title: 'Client-Retention',
// },
// ];

const Landing = ({ heading,numbers,button,paragraph }) => {


const Landing = ({ data }) => {
useEffect(() => {
//console.log(data);
}, [])
return ( return (
<Wrapper> <Wrapper>
<div className="flex flex-col gap-90p pb-164p"> <div className="flex flex-col gap-90p pb-164p">
<HiringWidget /> <HiringWidget />
<div className="mb-16 -mt-12 md:mt-5 flex flex-col lg:flex-row justify-between items-center gap-90p"> <div className="mb-16 -mt-12 md:mt-5 flex flex-col lg:flex-row justify-between items-center gap-90p">
<div className="flex flex-col gap-8p"> <div className="flex flex-col gap-8p">
<h1 className="subheading">{data.subheading}</h1>
<h2 className="heading">Software Solutions Tailored to Each Client</h2>
<p className="paragraph">{data.paragraph}</p>
<h6 className="subheading">
{heading.subtitle}
</h6>
<h1 className="heading">
{heading.title}
</h1>
<p className="paragraph">
{paragraph}

</p>
</div> </div>
<a <a
href="#contact" href="#contact"
className="btn-primary px-64p py-20p w-full lg:w-max whitespace-nowrap" className="btn-primary px-64p py-20p w-full lg:w-max whitespace-nowrap"
> >
{_data.cto}
{button}
</a> </a>
</div> </div>
</motion.section> </motion.section>
<div key={i} className="flex flex-col"> <div key={i} className="flex flex-col">
<p className="display-number text-center"> <p className="display-number text-center">
{item.value} {item.value}
{item.static}
</p> </p>
<h3 className="number-title text-center">{item.title}</h3> <h3 className="number-title text-center">{item.title}</h3>
</div> </div>

+ 2
- 2
frontend/src/components/Map.jsx Просмотреть файл

subheading: 'our office', subheading: 'our office',
} }


const MapDilig = () => {
const MapDilig = ({heading}) => {
return ( return (
<Wrapper padding={' py-90p'}> <Wrapper padding={' py-90p'}>
<PageTitle heading={data.heading} subheading={data.subheading} />
<PageTitle heading={heading.title} subheading={heading.subtitle} />
<div className='w-full py-90p'> <div className='w-full py-90p'>
<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2903.249778965247!2d21.90917771571484!3d43.30903038263504!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x4755b098fd2d0343%3A0x25c74e5a7a3a0530!2z0JfQtdGC0YHQutCwIDM2LCDQndC40Yg!5e0!3m2!1ssr!2srs!4v1666617514841!5m2!1ssr!2srs" width="100%" height="450" loading="lazy"></iframe> <iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2903.249778965247!2d21.90917771571484!3d43.30903038263504!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x4755b098fd2d0343%3A0x25c74e5a7a3a0530!2z0JfQtdGC0YHQutCwIDM2LCDQndC40Yg!5e0!3m2!1ssr!2srs!4v1666617514841!5m2!1ssr!2srs" width="100%" height="450" loading="lazy"></iframe>
</div> </div>

+ 0
- 4
frontend/src/components/PortfolioCard.jsx Просмотреть файл

const PortfolioCard = ({ title, isLarge, link, img, alt }) => { const PortfolioCard = ({ title, isLarge, link, img, alt }) => {
const linkTo = useNavigate(); const linkTo = useNavigate();


useEffect(() => {
//console.log(isLarge);
});

return ( return (
// <div className={"card box" + (isLarge ? ' col-span-2' : '')}> // <div className={"card box" + (isLarge ? ' col-span-2' : '')}>
<a className={'card box my-2 flex- flex-col items-center'} href={link}> <a className={'card box my-2 flex- flex-col items-center'} href={link}>

+ 3
- 3
frontend/src/components/PortfolioSection.jsx Просмотреть файл

], ],
}; };


function PortfolioSection() {
function PortfolioSection({heading,cta}) {
const linkTo = useNavigate(); const linkTo = useNavigate();


return ( return (
<Wrapper padding={' py-90p'} bg> <Wrapper padding={' py-90p'} bg>
<div className="py-32p"> <div className="py-32p">
<PageTitle left heading={'Case Studies'} subheading={'our Work'} />
<PageTitle left heading={heading.title} subheading={heading.subtitle} />
</div> </div>


<div className="flex flex-col lg:flex-row justify-center items-center lg:justify-between gap-8"> <div className="flex flex-col lg:flex-row justify-center items-center lg:justify-between gap-8">
> >
<img src={item.imgUrl} alt={item.alt} className={'mb-12'}></img> <img src={item.imgUrl} alt={item.alt} className={'mb-12'}></img>
<h3 className="h3-heading">{item.title}</h3> <h3 className="h3-heading">{item.title}</h3>
<button className="btn text-dg-secondary mt-4">Read More</button>
<button className="btn text-dg-secondary mt-4">{cta}</button>
</a> </a>
))} ))}
</div> </div>

+ 42
- 45
frontend/src/components/ProcessSection.jsx Просмотреть файл

import React, { useEffect, useState } from 'react'
import PageTitle from './shared/PageTitle'
import {ReactComponent as ProcessSvg} from './../assets/images/Process.svg';
import React, { useEffect, useState } from 'react';
import PageTitle from './shared/PageTitle';
import { ReactComponent as ProcessSvg } from './../assets/images/Process.svg';
import Wrapper from '../layout/Wrapper'; import Wrapper from '../layout/Wrapper';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import ProcessSlider from './ProcessSlider'; import ProcessSlider from './ProcessSlider';
import { useWindowInfo } from '@faceless-ui/window-info'; import { useWindowInfo } from '@faceless-ui/window-info';
import useWindowSize from '../hooks/useWindowSize'; import useWindowSize from '../hooks/useWindowSize';



const _data = { const _data = {
heading: "How We Do It",
subheading: "Our process",
imgUrl: "",
btn: "check it out"
}
heading: 'How We Do It',
subheading: 'Our process',
imgUrl: '',
btn: 'check it out',
};


const ProcessSection = () => {
const api_url = process.env.REACT_APP_API_URL;


const ProcessSection = ({ image, imageAlt, heading, btn, mobileImages }) => {
const [isMobile, setIsMobile] = useState(false); const [isMobile, setIsMobile] = useState(false);


const windowInfo = useWindowSize(); const windowInfo = useWindowSize();


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


const link = useNavigate(); const link = useNavigate();


return ( return (
<Wrapper padding={" py-90p"} hideOverflow>
<div className='w-full'>
<PageTitle heading={_data.heading} subheading={_data.subheading} color left />
</div>
<div className="relative mx-auto my-32p md:my-90p">
{!isMobile ? (
<div className='w-full' draggable >
<ProcessSvg className='' />
</div>
) :
(
<div className='' >
<ProcessSlider/>
</div>
)
}
<Wrapper padding={' py-90p'} hideOverflow>
<div className="w-full">
{heading ? (
<PageTitle
heading={heading.title}
subheading={heading.subtitle}
color
left
/>
) : null}
</div>

<div className="relative mx-auto my-32p md:my-90p">
{!isMobile ? (
<div className="w-full">
{image ? <img src={api_url + image.data.attributes.url} alt={image.data.attributes.alternativeText}></img> : null}
</div> </div>
<div className='flex justify-center w-full'>
<button className="btn-secondary" onClick={()=>link('/process')}>{_data.btn}</button>
) : (
<div className="">
<ProcessSlider images={mobileImages.data} />
</div> </div>
)}
</div>
<div className="flex justify-center w-full">
<button className="btn-secondary" onClick={() => link('/process')}>
{btn}
</button>
</div>
</Wrapper> </Wrapper>
)
}
);
};


export default ProcessSection
export default ProcessSection;

+ 2
- 2
frontend/src/components/ProcessSlider.jsx Просмотреть файл

import ProcessSliderWrapper from './shared/ProcessSliderWrapper' import ProcessSliderWrapper from './shared/ProcessSliderWrapper'
import ProcessFacelessSlider from './shared/ProcessFacelessSlider' import ProcessFacelessSlider from './shared/ProcessFacelessSlider'


const ProcessSlider = props => {
const ProcessSlider = ({images}) => {
return ( return (
<> <>
<ProcessSliderWrapper> <ProcessSliderWrapper>
<ProcessFacelessSlider/>
<ProcessFacelessSlider images={images}/>
</ProcessSliderWrapper> </ProcessSliderWrapper>
</> </>

+ 0
- 1
frontend/src/components/ServicesHome.jsx Просмотреть файл

`${api_url}/api/homepage?populate[0]=services&populate[1]=services.heading&populate[2]=services.serviceHome.icon`, `${api_url}/api/homepage?populate[0]=services&populate[1]=services.heading&populate[2]=services.serviceHome.icon`,
) )
.then(res => { .then(res => {
//console.log(res.data.data.attributes);
setCntServicesHome(res.data.data.attributes); setCntServicesHome(res.data.data.attributes);
setIsLoaded(true); setIsLoaded(true);
}) })

+ 3
- 3
frontend/src/components/TechStack.jsx Просмотреть файл

paragraph: "And many more..." paragraph: "And many more..."
} }


function TechStack() {
function TechStack({heading, btn}) {
return ( return (
<Wrapper bg padding={" py-90p"}> <Wrapper bg padding={" py-90p"}>
<div className='flex flex-col gap-90p justify-center items-center'> <div className='flex flex-col gap-90p justify-center items-center'>
<div className='w-full'> <div className='w-full'>
<PageTitle heading={_data.heading} subheading={_data.subheading} left />
<PageTitle heading={heading.title} subheading={heading.subtitle} left />
</div> </div>
<div className='w-full'> <div className='w-full'>
<StackWrapper /> <StackWrapper />
</div> </div>
<p className='paragraph'>{_data.paragraph}</p>
<p className='paragraph'>{btn}</p>
</div> </div>
</Wrapper> </Wrapper>

+ 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>

+ 18
- 18
frontend/src/components/WhySection.jsx Просмотреть файл

}, },
}; };


const WhySection = ({ data }) => {
const WhySection = ({ heading,cards,p1,p2 }) => {
return ( return (
<Wrapper bg hideOverflow> <Wrapper bg hideOverflow>
<div className="relative"> <div className="relative">


<motion.section <motion.section
id="why_us" id="why_us"
className=" flex flex-col items-center relative pt-164p pb-240p"
className=" flex flex-col items-center relative pt-64p lg:pt-164p pb-[144px]"
> >
<div className="flex flex-col justify-center items-center gap-90p"> <div className="flex flex-col justify-center items-center gap-90p">
<div className="max-w-[780px]"> <div className="max-w-[780px]">
<PageHeading <PageHeading
subheading={_data.heading.subheading}
heading={_data.heading.heading}
paragraph1={_data.heading.paragraph1}
paragraph2={_data.heading.paragraph2}
subheading={heading.subtitle}
heading={heading.title}
paragraph1={p1}
paragraph2={p2}
/> />
</div> </div>


transition={{ delay: 0, default: { duration: 0.45 } }} transition={{ delay: 0, default: { duration: 0.45 } }}
> >
<WhyUsCard <WhyUsCard
image={_data.card_left.imgUrl}
alt={_data.card_left.alt}
heading={_data.card_left.heading}
paragraph={_data.card_left.paragraph}
image={cards.Card1.Image.data.attributes.url}
alt={cards.Card1.Image.data.attributes.alternativeText}
heading={cards.Card1.Title}
paragraph={cards.Card1.paragraph}
/> />
</motion.div> </motion.div>
{/* Card - mid */} {/* Card - mid */}
transition={{ delay: 0.27, default: { duration: 0.45 } }} transition={{ delay: 0.27, default: { duration: 0.45 } }}
> >
<WhyUsCard <WhyUsCard
image={_data.card_mid.imgUrl}
alt={_data.card_mid.alt}
heading={_data.card_mid.heading}
paragraph={_data.card_mid.paragraph}
image={cards.Card2.Image.data.attributes.url}
alt={cards.Card2.Image.data.attributes.alternativeText}
heading={cards.Card2.Title}
paragraph={cards.Card2.paragraph}
/> />
</motion.div> </motion.div>
{/* Card - right */} {/* Card - right */}
transition={{ delay: 0.54, default: { duration: 0.45 } }} transition={{ delay: 0.54, default: { duration: 0.45 } }}
> >
<WhyUsCard <WhyUsCard
image={_data.card_right.imgUrl}
alt={_data.card_right.alt}
heading={_data.card_right.heading}
paragraph={_data.card_right.paragraph}
image={cards.Card3.Image.data.attributes.url}
alt={cards.Card3.Image.data.attributes.alternativeText}
heading={cards.Card3.Title}
paragraph={cards.Card3.paragraph}
/> />
</motion.div> </motion.div>
</div> </div>

+ 3
- 1
frontend/src/components/WhyUsCard.jsx Просмотреть файл

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


const api_url = process.env.REACT_APP_API_URL;

export default function WhyUsCard(props) { export default function WhyUsCard(props) {
return ( return (
<div className="card-no-hover w-fit h-full flex flex-col text-center justify-between group"> <div className="card-no-hover w-fit h-full flex flex-col text-center justify-between group">
<img <img
src={props.image}
src={api_url + props.image}
alt={props.alt} alt={props.alt}
className="ml-auto mr-auto block w-2/5 bg-baby-blue text-dark-gray rounded-full" className="ml-auto mr-auto block w-2/5 bg-baby-blue text-dark-gray rounded-full"
/> />

+ 153
- 0
frontend/src/components/WorkClientForm.jsx Просмотреть файл

import React from 'react';
import CustomLink from './root/CustomLink';
import * as Yup from 'yup';
import { Formik, Form, ErrorMessage } from 'formik';
import { useState, useRef } from 'react';

const WorkClientForm = ({ data, download, onValidated, message, status }) => {
const container = useRef();
const [suc, setSuc] = useState(false);
const [form, setForm] = useState({
name: '',
surname: '',
email: '',
});

const validationSchema = Yup.object({
name: Yup.string()
.min(2, 'First name too short')
.max(50, 'First name too long')
.required('First Name is Required'),
email: Yup.string().email('Invalid email format').required('Email is Required'),
surname: Yup.string()
.min(2, 'Last name too short')
.max(50, 'Last name too long')
.required('Last Name is Required'),
});

return (
<div
ref={container}
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.title}</h6>
<p className="n-paragraph">{data.paragraph}</p>
<Formik
initialValues={form}
validationSchema={validationSchema}
onSubmit={async values => {
setForm({
...form,
name: values.name,
surname: values.surname,
email: values.email,
});
onValidated({
FNAME: values.name,
LNAME: values.surname,
EMAIL: values.email,
});
}}
>
{props => (
<Form onSubmit={props.handleSubmit}>
<div className=" sm:rounded-md">
<div className="py-2 sm:py-6">
<div className="">
<div className="col-span-1 sm:col-span-1">
<div className="py-1">
<label
htmlFor="name"
className="block text-sm font-medium text-gray-700 dark:text-gray-400"
>
First name
</label>
<input
type="text"
name="name"
id="name"
onChange={props.handleChange}
value={props.values.name}
autoComplete="given-name"
className="mt-1 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 className="h-4">
<ErrorMessage
name="name"
component="div"
className="text-sm text-right text-red-600"
/>
</div>
</div>
<div className="py-1">
<label
htmlFor="surname"
className="block text-sm font-medium text-gray-700 dark:text-gray-400"
>
Last name
</label>
<input
type="text"
name="surname"
id="surname"
onChange={props.handleChange}
value={props.values.surname}
autoComplete="family-name"
className="mt-1 focus:ring-dg-primary-900 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 className="h-4">
<ErrorMessage
name="surname"
component="div"
className="text-sm text-right text-red-600"
/>
</div>
</div>
<div className="py-1">
<label
htmlFor="email"
className="block text-sm font-medium text-gray-700 dark:text-gray-400"
>
Email
</label>
<input
type="email"
name="email"
id="email"
onChange={props.handleChange}
value={props.values.email}
autoComplete="email"
className="mt-1 focus:ring-dg-primary-900 focus:border-dg-primary-900 dark:bg-dg-primary-1500 dark:text-white dark:autofill:text-white dark:autofill:bg-dg-primary-1500 block w-full shadow-sm sm:text-sm border-dg-primary-600 rounded-md transition duration-200"
/>
<div className="h-4">
<ErrorMessage
name="email"
component="div"
className="text-sm text-right text-red-600"
/>
</div>
</div>

<div className=" py-3 text-right">
<button
type="submit"
className="btn-primary w-fit items-center n-paragraph-title text-white rounded-[16px]"
>
Subscribe and Download
</button>
<div className="text-sm text-right text-red-600">{message}</div>
</div>
</div>
</div>
</div>
</div>
</Form>
)}
</Formik>
</div>
</div>
);
};

export default WorkClientForm;

+ 9
- 11
frontend/src/components/root/CustomLink.jsx Просмотреть файл





return ( return (
// <a href={href} {...(downloadFile && { download="My_File.pdf" })} (downloadFile download="My_File.pdf")>
// {context}
// </a>
<Link {...{
className: 'btn-primary w-fit items-center n-paragraph-title text-white rounded-[16px]' ,
to: href,
target: '_blank',
...(downloadFile && {download: downloadFile}),
}}>
{children}
</Link>
<div className='btn-primary w-fit items-center n-paragraph-title text-white rounded-[16px]'>{children}</div>
// <Link {...{
// className: 'btn-primary w-fit items-center n-paragraph-title text-white rounded-[16px]' ,
// to: href,
// target: '_blank',
// ...(downloadFile && {download: downloadFile}),
// }}>
// {children}
// </Link>
) )
} }



+ 1
- 1
frontend/src/components/shared/CardValues.jsx Просмотреть файл

return ( return (
<div className="flex flex-col justify-center items-start text-left card-no-hover w-full"> <div className="flex flex-col justify-center items-start text-left card-no-hover w-full">
<div className="flex flex-row justify-start items-center"> <div className="flex flex-row justify-start items-center">
<img src={props.image} alt="Icon" width={27} />
<img src={props.image} alt={props.alt} width={27} />
<h3 className="h3-heading ml-2">{props.heading}</h3> <h3 className="h3-heading ml-2">{props.heading}</h3>
</div> </div>
<p className="paragraph mt-2">{props.paragraph}</p> <p className="paragraph mt-2">{props.paragraph}</p>

+ 15
- 4
frontend/src/components/shared/ClientForm.jsx Просмотреть файл

import ReactGA from 'react-ga4'; import ReactGA from 'react-ga4';
import ReCAPTCHA from 'react-google-recaptcha'; import ReCAPTCHA from 'react-google-recaptcha';
import axios from 'axios'; import axios from 'axios';
import { useEffect } from 'react';


export default function ClientForm({ mg }) {
const api_url = process.env.REACT_APP_API_URL;

export default function ClientForm({ mg, img, cta }) {
//search context for prevous entry TODO //search context for prevous entry TODO
const [btnText, setBtnText] = useState('');
const { clientForm, setClientForm } = useContext(ClientFormContext); const { clientForm, setClientForm } = useContext(ClientFormContext);
const [sucMsg, setSucMsg] = useState(false); const [sucMsg, setSucMsg] = useState(false);
const captchaRef = useRef(null); const captchaRef = useRef(null);
}); });
}; };


useEffect(() => {
setBtnText(cta);
},[cta]);




const validationSchema = Yup.object({ const validationSchema = Yup.object({
subject: Yup.string() subject: Yup.string()
.min(2, 'Subject too short') .min(2, 'Subject too short')
} else setMsgText('Please fill reCAPTCHA and try again. Thank you!'); } else setMsgText('Please fill reCAPTCHA and try again. Thank you!');
}) })
.catch(error => { .catch(error => {
console.log(error);
//console.log(error);
}); });
} }
ReactGA.event('contact', { ReactGA.event('contact', {
type="submit" type="submit"
className="btn btn_primary transition-all inline-flex justify-center py-4 px-14 border border-transparent shadow-md text-sm font-semibold rounded-xl text-white bg-dg-primary-600 hover:bg-dg-primary-900 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-dg-primary-600" className="btn btn_primary transition-all inline-flex justify-center py-4 px-14 border border-transparent shadow-md text-sm font-semibold rounded-xl text-white bg-dg-primary-600 hover:bg-dg-primary-900 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-dg-primary-600"
> >
Submit
{btnText}
</button> </button>
</div> </div>
{sucMsg && ( {sucMsg && (
exit={{ x: 60, opacity: 0 }} exit={{ x: 60, opacity: 0 }}
transition={{ duration: 0.3, ease: 'easeOut' }} transition={{ duration: 0.3, ease: 'easeOut' }}
> >
<img src={img} alt="Our Team's image" />
<img src={api_url + img.data.attributes.url} alt={img.data.attributes.alternativeText} />
</motion.div> </motion.div>
</div> </div>
</div> </div>

+ 18
- 14
frontend/src/components/shared/Contact.jsx Просмотреть файл

url: 'https://api.eu.mailgun.net', url: 'https://api.eu.mailgun.net',
}); });


export default function Contact(props) {
const [tab, setTab] = useState(true);
const [tabTitle, setTabTitle] = useState('Tell Us About Your Idea!');
export default function Contact({activeTab, position, job, business}) {
const [tab, setTab] = useState(activeTab);
const [tabTitle, setTabTitle] = useState(business.title);


function handleContextMenu(event) { function handleContextMenu(event) {
event.preventDefault(); event.preventDefault();
function handleTab(tabIndex) { function handleTab(tabIndex) {
if (tabIndex == 0) { if (tabIndex == 0) {
setTab(true); setTab(true);
setTabTitle('Tell Us About Your Idea!');
setTabTitle(business.title);
} else { } else {
setTab(false); setTab(false);
setTabTitle('Join Diligent!');
setTabTitle(job.title);
} }
} }




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


let defaultPositionSelection = props.defaultPositionSelection;

const [clientForm, setClientForm] = useState(initialClientValues); const [clientForm, setClientForm] = useState(initialClientValues);
const [jobForm, setJobForm] = useState(initialJobValues); const [jobForm, setJobForm] = useState(initialJobValues);


`${api_url}/api/careerspage?populate[0]=heading&populate[1]=info&populate[2]=job.icon`, `${api_url}/api/careerspage?populate[0]=heading&populate[1]=info&populate[2]=job.icon`,
) )
.then(res => { .then(res => {
//console.log(res.data.data.attributes);
setCntCareers(res.data.data.attributes); setCntCareers(res.data.data.attributes);
setIsLoaded(true); setIsLoaded(true);
}) })
}); });
}, []); }, []);


useEffect(() => {
console.log(position);
})

if (!isLoaded) { if (!isLoaded) {
return ( 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"> <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">
<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={tab ? 0 : 1}
onChange={index => handleTab(index)} onChange={index => handleTab(index)}
> >
<div <div
{tab ? ( {tab ? (
<PageTitle <PageTitle
left left
heading={'Tell Us About Your Idea!'}
subheading={'Contact us'}
heading={business.title}
subheading={business.subtitle}
/> />
) : ( ) : (
<PageTitle left heading={'Join Diligent!'} subheading={'Cotact us'} />
<PageTitle left heading={job.title} subheading={job.title} />
)} )}


<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.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 mg={mg} />
<ClientForm mg={mg}
cta={business.cta}
img={business.image} />
</ClientFormContext.Provider> </ClientFormContext.Provider>
</Tab.Panel> </Tab.Panel>
<Tab.Panel className={classNames('py-3', 'outline-none')}> <Tab.Panel className={classNames('py-3', 'outline-none')}>
<JobFormContext.Provider value={{ jobForm, setJobForm }}> <JobFormContext.Provider value={{ jobForm, setJobForm }}>
<JobForm <JobForm
cta={job.cta}
img={job.image}
cntCareers={cntCareers} cntCareers={cntCareers}
defaultPositionSelection={defaultPositionSelection}
mg={mg} mg={mg}
/> />
</JobFormContext.Provider> </JobFormContext.Provider>

+ 3
- 2
frontend/src/components/shared/HashPositions.jsx Просмотреть файл



export default function HashPositions(props) { export default function HashPositions(props) {
let defaultPositionSelection = props.defaultPositionSelection; let defaultPositionSelection = props.defaultPositionSelection;
//let defaultPositionSelection = '#dotNet';
//const cntCareersJobs = props.cntCareers; //const cntCareersJobs = props.cntCareers;
let [selected, setSelected] = useState('#dotNet');
let [selected, setSelected] = useState('');


function handleChange(event) { function handleChange(event) {
setSelected(event.target.innerText); setSelected(event.target.innerText);
<span <span
onClick={() => { onClick={() => {
props.setOtherInputState(true); props.setOtherInputState(true);
defaultPositionSelection = '';
defaultPositionSelection = '#dotNet';
handleChange(event); handleChange(event);
props.hashToFormData(selected); props.hashToFormData(selected);
}} }}

+ 12
- 4
frontend/src/components/shared/JobForm.jsx Просмотреть файл

import ReCAPTCHA from 'react-google-recaptcha'; import ReCAPTCHA from 'react-google-recaptcha';
import axios from 'axios'; import axios from 'axios';


const api_url = process.env.REACT_APP_API_URL;

export default function JobForm(props) { export default function JobForm(props) {
const [btnText, setBtnText] = useState('');
const [sucMsg, setSucMsg] = useState(false); const [sucMsg, setSucMsg] = useState(false);
const captchaRef = useRef(null); const captchaRef = useRef(null);
const [msgText, setMsgText] = useState(''); const [msgText, setMsgText] = useState('');
}); });
} }


useEffect(() => {
setBtnText(props.cta);
},[props.cta])

useEffect(() => { useEffect(() => {
if (jobForm.file !== '') { if (jobForm.file !== '') {
setErrorMsg(''); setErrorMsg('');
name="position" name="position"
id="position" id="position"
onBlur={changeFormHandler} onBlur={changeFormHandler}
value={selectedPosition.substring(1)}
value={selectedPosition.substring(1) || 0}
onChange={props.handleChange} onChange={props.handleChange}
autoComplete="given-name" autoComplete="given-name"
className="mt-1 disabled:bg-gray-100 disabled:border-gray-300 focus:ring-dg-primary-600 focus:border-dg-primary-900 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 focus:ring-dg-primary-600 focus:border-dg-primary-900 block w-full shadow-sm sm:text-sm border-dg-primary-600 rounded-md transition duration-200"
type="submit" type="submit"
className="btn btn_primary transition-all inline-flex justify-center py-4 px-14 border border-transparent shadow-md text-sm font-semibold rounded-xl text-white bg-dg-primary-600 hover:bg-dg-primary-900 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-dg-primary-600" className="btn btn_primary transition-all inline-flex justify-center py-4 px-14 border border-transparent shadow-md text-sm font-semibold rounded-xl text-white bg-dg-primary-600 hover:bg-dg-primary-900 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-dg-primary-600"
> >
Submit
</button>
{btnText}
</button>
</div> </div>
{sucMsg && ( {sucMsg && (
<div className={'text-sm text-right text-dg-primary-900'}> <div className={'text-sm text-right text-dg-primary-900'}>
exit={{ x: 60, opacity: 0 }} exit={{ x: 60, opacity: 0 }}
transition={{ duration: 0.3, ease: 'easeOut' }} transition={{ duration: 0.3, ease: 'easeOut' }}
> >
<img src={img} alt="Our Team's image" />
<img src={api_url + props.img.data.attributes.url} alt={props.img.data.attributes.alternativeText} />
</motion.div> </motion.div>
</div> </div>
</div> </div>

+ 110
- 27
frontend/src/components/shared/Navigation.jsx Просмотреть файл

import '../../App.css'; import '../../App.css';
import Wrapper from '../../layout/Wrapper'; import Wrapper from '../../layout/Wrapper';
import menuIcon from './../../assets/icons/menu.svg'; import menuIcon from './../../assets/icons/menu.svg';
import chevron from './../../assets/chevron.svg';
import { useState } from 'react';
import useHoverOtuside from '../../hooks/useHoverOutside';
import { ref } from 'yup';


export default function Navigation({ links, scrollToView, activeLinks, forwardedRef }) { export default function Navigation({ links, scrollToView, activeLinks, forwardedRef }) {
const location = useLocation(); const location = useLocation();
home('/'); home('/');
} }


const { ref, show, setShow } = useHoverOtuside(false);


function showDrop() {
setShow(!show);
}


// Check if you are on HomePage to scroll to Contact us, or open a sepperate Contact us Page // Check if you are on HomePage to scroll to Contact us, or open a sepperate Contact us Page
function checkUrl(event) { function checkUrl(event) {
as="nav" as="nav"
className="hidden md:flex space-x-8 lg:space-x-10 items-center" className="hidden md:flex space-x-8 lg:space-x-10 items-center"
> >
{links.map((item,index) => (
<NavLink
key={index}
to={item.path}
className={({ isActive }) => {
return `text-p font-medium dark:text-white hover:text-dg-primary-900 focus:text-dg-primary-900 active:text-dg-primary-900 capitalize ${activeLinks(
isActive,
)}`;
}}
>
{item.title}
</NavLink>
))}
{links.map((item, index) =>
(item.drop && item.drop > 0) ? (
<div>
<a
href={item.path}
onMouseOver={() => showDrop()}
id="dropdownNavbarLink"
className="flex items-center justify-between w-full py-2 pl-3 pr-4 font-medium rounded text-gray-500 hover:text-dg-primary-900 focus:text-dg-primary-900 active:text-dg-primary-900 md:dark:hover:bg-transparent"
>
Careers
<svg
className="w-5 h-5 ml-1"
aria-hidden="true"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
></path>
</svg>
</a>
<div
ref={ref}
id="dropdownNavbar"
className={
(show ? 'absolute ' : 'hidden ') +
'z-10 font-normal bg-white divide-y divide-gray-100 rounded-lg shadow w-44 dark:bg-gray-700 dark:divide-gray-600'
}
>
<ul className="py-8 px-8 text-sm text-gray-500 dark:text-gray-400">
{item.drop.map((item2, index2) => (
<li key={index2}>
<a
href={item2.path}
className="text-p font-medium text-gray-500 dark:text-white hover:text-dg-primary-900 focus:text-dg-primary-900 active:text-dg-primary-900 capitalize whitespace-nowrap"
>
{item2.title}
</a>
</li>
))}
</ul>
</div>
</div>
) : (
<NavLink
key={index}
to={item.path}
className={({ isActive }) => {
return `text-p font-medium dark:text-white hover:text-dg-primary-900 focus:text-dg-primary-900 active:text-dg-primary-900 capitalize ${activeLinks(
isActive,
)}`;
}}
>
{item.title}
</NavLink>
),
)}
{/* React Router Link does not support Anchor tags */} {/* React Router Link does not support Anchor tags */}
<div <div
// onClick={event => scrollToView(event)}
onClick={event => checkUrl(event)} onClick={event => checkUrl(event)}
href="#contact" href="#contact"
className="contact-us-link text-p" className="contact-us-link text-p"
</div> </div>
<div className="mt-6"> <div className="mt-6">
<nav className="grid gap-y-8"> <nav className="grid gap-y-8">
{links.map((item,index) => (
<NavLink
onClick={() => close()}
key={index}
to={item.path}
className="text-p p-3 flex justify-center items-center rounded-md transition-all hover:transition-all hover:bg-dg-primary-900 hover:text-white"
>
<div aria-hidden="true" />
<span className="ml-3 text-base font-medium text-inherit">
{item.title}
</span>
</NavLink>
))}
{links.map((item, index) =>
item.drop ? (
<>
<NavLink
onClick={() => close()}
key={index}
to={item.path}
className="text-p p-3 flex justify-center items-center rounded-md transition-all hover:transition-all hover:bg-dg-primary-900 hover:text-white"
>
<div aria-hidden="true" />
<span className="ml-3 text-base font-medium text-inherit">
{item.title}
</span>
</NavLink>
{item.drop.map((item2, index2) => (
<NavLink
onClick={() => close()}
key={index2}
to={item2.path}
className="text-p p-3 flex justify-center items-center rounded-md transition-all hover:transition-all hover:bg-dg-primary-900 hover:text-white"
>
<div aria-hidden="true" />
<span className="ml-3 text-base font-medium text-inherit">
{item2.title}
</span>
</NavLink>
))}
</>
) : (
<NavLink
onClick={() => close()}
key={index}
to={item.path}
className="text-p p-3 flex justify-center items-center rounded-md transition-all hover:transition-all hover:bg-dg-primary-900 hover:text-white"
>
<div aria-hidden="true" />
<span className="ml-3 text-base font-medium text-inherit">
{item.title}
</span>
</NavLink>
),
)}
<a <a
href="#contact" href="#contact"
onClick={event => { onClick={event => {

+ 179
- 0
frontend/src/components/shared/NavigationNew.jsx Просмотреть файл

import { Fragment } from 'react';
import { Popover, Transition } from '@headlessui/react';
import PropTypes from 'prop-types';

import logo from '../../assets/logos/LogoFull.svg';
import { NavLink, useLocation, useNavigate } from 'react-router-dom';
import '../../App.css';
import Wrapper from '../../layout/Wrapper';
import menuIcon from './../../assets/icons/menu.svg';
import { useState } from 'react';

export default function NavigationNew({
links,
scrollToView,
activeLinks,
forwardedRef,
}) {
const [drop, setDrop] = useState(false);
const location = useLocation();
const home = useNavigate();
function handleLogo() {
home('/');
}

function showDrop() {
setDrop(!drop);
}

// Check if you are on HomePage to scroll to Contact us, or open a sepperate Contact us Page
function checkUrl(event) {
if (location.pathname === '/') scrollToView(event);
else home('/contact');
}

return (
<>
<nav className="bg-white dark:bg-dg-primary-1700 fixed w-full top-0 z-50">
<div className="container flex flex-wrap items-center justify-between mx-auto">
<a href="/" className="flex items-center">
<img src={logo} className="h-6 mr-3 sm:h-10" alt="Diligent Logo" />
</a>
<button
data-collapse-toggle="navbar-dropdown"
type="button"
className="inline-flex items-center p-2 ml-3 text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600"
aria-controls="navbar-dropdown"
aria-expanded="false"
>
<span className="sr-only">Open main menu</span>
<svg
className="w-6 h-6"
aria-hidden="true"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z"
clipRule="evenodd"
></path>
</svg>
</button>
<div className="hidden w-full md:block md:w-auto" id="navbar-dropdown">
<ul className="flex flex-col p-4 mt-4 border border-gray-100 rounded-lg bg-gray-50 md:flex-row md:space-x-8 md:mt-0 md:text-sm md:font-medium md:border-0 md:bg-white dark:bg-gray-800 md:dark:bg-gray-900 dark:border-gray-700">
<li>
<a
href="#"
className="block py-2 pl-3 pr-4 text-white bg-blue-700 rounded md:bg-transparent md:text-blue-700 md:p-0 md:dark:text-white dark:bg-blue-600 md:dark:bg-transparent"
aria-current="page"
>
Home
</a>
</li>
<li>
<button
onClick={() => showDrop()}
id="dropdownNavbarLink"
className="flex items-center justify-between w-full py-2 pl-3 pr-4 font-medium text-gray-700 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 md:w-auto dark:text-gray-400 dark:hover:text-white dark:focus:text-white dark:border-gray-700 dark:hover:bg-gray-700 md:dark:hover:bg-transparent"
>
Dropdown{' '}
<svg
className="w-5 h-5 ml-1"
aria-hidden="true"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
></path>
</svg>
</button>
{/* <!-- Dropdown menu --> */}
<div
id="dropdownNavbar"
className={
(drop ? 'block ' : 'hidden ') +
'z-10 font-normal bg-white divide-y divide-gray-100 rounded-lg shadow w-44 dark:bg-gray-700 dark:divide-gray-600'
}
>
<ul
className="py-2 text-sm text-gray-700 dark:text-gray-400"
aria-labelledby="dropdownLargeButton"
>
<li>
<a
href="#"
className="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white"
>
Dashboard
</a>
</li>
<li>
<a
href="#"
className="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white"
>
Settings
</a>
</li>
<li>
<a
href="#"
className="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white"
>
Earnings
</a>
</li>
</ul>
<div className="py-1">
<a
href="#"
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-400 dark:hover:text-white"
>
Sign out
</a>
</div>
</div>
</li>
<li>
<a
href="#"
className="block py-2 pl-3 pr-4 text-gray-700 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-gray-400 md:dark:hover:text-white dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent"
>
Services
</a>
</li>
<li>
<a
href="#"
className="block py-2 pl-3 pr-4 text-gray-700 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-gray-400 md:dark:hover:text-white dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent"
>
Pricing
</a>
</li>
<li>
<a
href="#"
className="block py-2 pl-3 pr-4 text-gray-700 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-gray-400 md:dark:hover:text-white dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent"
>
Contact
</a>
</li>
</ul>
</div>
</div>
</nav>
</>
);
}

NavigationNew.propTypes = {
links: PropTypes.arrayOf(PropTypes.object),
scrollToView: PropTypes.func,
activeLinks: PropTypes.func,
};

+ 4
- 2
frontend/src/components/shared/PageHeading.jsx Просмотреть файл

export default function PageHeading(props) { export default function PageHeading(props) {
return ( return (
<div className="flex flex-col gap-8p items-center justify-center"> <div className="flex flex-col gap-8p items-center justify-center">
<h2 className="subheading">{props.subheading}</h2>
<h3 className="heading text-center">{props.heading}</h3>
<div className="mb-32p lg:mb-64p flex flex-col gap-8p items-center justify-center">
<h2 className="subheading">{props.subheading}</h2>
<h3 className="heading text-center">{props.heading}</h3>
</div>
<div className="flex flex-col gap-16p"> <div className="flex flex-col gap-16p">
<p className="paragraph text-start">{props.paragraph1}</p> <p className="paragraph text-start">{props.paragraph1}</p>
<p className="paragraph text-start">{props.paragraph2}</p> <p className="paragraph text-start">{props.paragraph2}</p>

+ 3
- 3
frontend/src/components/shared/PageTitle.jsx Просмотреть файл



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' :' ')}>
<h6 className={"subheading" + (left ? " text-left":" text-center")}>{subheading}</h6>
<h1 className={"heading" + (left ? " text-left":" text-center")}>{heading}</h1>
<div className={"flex flex-col gap-8p"+ (left ? " text-left items-start":" text-center items-center") + (color ? " text-dg-secondary" : " ") + (pb ? ' pb-2' :' ')}>
<h6 className={"subheading " + (left ? " text-left":" text-center")}>{subheading}</h6>
<h1 className={"heading text-inherit" + (left ? " text-left":" text-center")}>{heading}</h1>
</div> </div>
) )
} }

+ 1
- 1
frontend/src/components/shared/ProcessCard.jsx Просмотреть файл

{paragraphs && {paragraphs &&
paragraphs.map((item, index) => ( paragraphs.map((item, index) => (
<p className="paragraph" key={index}> <p className="paragraph" key={index}>
{item.paragraph}
{item.ParagraphElement}
</p> </p>
))} ))}
</div> </div>

+ 6
- 4
frontend/src/components/shared/ProcessFacelessSlider.jsx Просмотреть файл

import ProcessSvgPart2 from './../../assets/ProcessPart2.svg'; import ProcessSvgPart2 from './../../assets/ProcessPart2.svg';
import ProcessSvgPart3 from './../../assets/ProcessPart3.svg'; import ProcessSvgPart3 from './../../assets/ProcessPart3.svg';


const slides = [ProcessSvgPart1, ProcessSvgPart2, ProcessSvgPart3];
const api_url = process.env.REACT_APP_API_URL;


const ProcessFacelessSlider = props => {
const ProcessFacelessSlider = ({images}) => {

const slides = [images[0].attributes,images[1].attributes, images[2].attributes];
return ( return (
<SliderProvider slidesToShow={1} scrollSnap dragScroll> <SliderProvider slidesToShow={1} scrollSnap dragScroll>
<div className={''}> <div className={''}>
{slides.map((slide, index) => ( {slides.map((slide, index) => (
<Slide key={index} index={index} className={'h-full'}> <Slide key={index} index={index} className={'h-full'}>
<img <img
src={slide}
alt={`step ${index + 1}`}
src={api_url + slide.url}
alt={slide.alternativeText}
className={'h-full mx-auto'} className={'h-full mx-auto'}
></img> ></img>
</Slide> </Slide>

+ 2
- 1
frontend/src/components/shared/ReactHelmet.jsx Просмотреть файл

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


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


const ReactHelmet = ({ seo }) => { const ReactHelmet = ({ seo }) => {
console.log(seo);
//console.log(seo);
return ( return (
<Helmet> <Helmet>
<title>{seo.metaTitle}</title> <title>{seo.metaTitle}</title>

+ 58
- 0
frontend/src/components/shared/VideoComponent.jsx Просмотреть файл

import React, { useRef } from 'react';

import { useState } from 'react';
import UseAnimations from 'react-useanimations';
import volume from 'react-useanimations/lib/volume';

const api_url = process.env.REACT_APP_API_URL;

const VideoComponent = ({ source, alt }) => {
const [mute, setMute] = useState(true);

const vidRef = useRef();
const muteRef = useRef();

function toggleMute() {
var video = vidRef.current;
video.muted = !video.muted;
setMute(!mute);
}

return (
<div className="w-full py-48p lg:py-72p relative">
<video autoPlay loop ref={vidRef} muted className="rounded-[32px]">
<source type="video/mp4" src={api_url + source} alt={api_url + alt} />
</video>
<div className="absolute bottom-16 right-4 md:bottom-24 md:right-8 rounded-full overflow-clip">
<UseAnimations
reverse={mute}
onClick={() => {
toggleMute();
}}
size={50}
wrapperStyle={{ background: 'white', padding: '5px' }}
animation={volume}
speed={0.7}
/>
</div>

{/* <div className="">
<button
className={'unmuted toggle-sound' + (mute ? ' sound-mute' : null)}
onClick={() => toggleMute()}
>
<div className="sound">
<div className="sound--icon">
<Speaker />
</div>
<div className="sound--wave sound--wave_one"></div>
<div className="sound--wave sound--wave_two"></div>
<div className="sound--wave sound--wave_three"></div>
</div>
</button>
</div> */}
</div>
);
};

export default VideoComponent;

+ 1
- 1
frontend/src/context/index.js Просмотреть файл

tab: true, tab: true,
contactRef: '', contactRef: '',
position: 0, position: 0,
})
});

+ 60
- 37
frontend/src/hooks/useDataApi.js Просмотреть файл







//Reducer
const dataFetchReducer = (state, action) => { const dataFetchReducer = (state, action) => {
switch (action.type) {
case 'FETCH_INIT':
return {
...state,
isLoading: true,
isError: false,
};
case 'FETCH_SUCCESS':
return {
...state,
isLoading: false,
isError: false,
data: action.payload,
};
case 'FETCH_FAILURE':
return {
...state,
isLoading: false,
isError: true,
};
default:
throw new Error();
}
};
switch (action.type) {
case 'FETCH_INIT':
return {
...state,
isLoading: true,
isError: false
};
case 'FETCH_SUCCESS':
return {
...state,
isLoading: false,
isError: false,
data: action.payload,
};
case 'FETCH_FAILURE':
return {
...state,
isLoading: false,
isError: true,
};
default:
throw new Error();
}
};



//hook
const useDataApi = (initialUrl, initialData) => { const useDataApi = (initialUrl, initialData) => {
const [url, setUrl] = useState(initialUrl);
const [state, dispatch] = useReducer(dataFetchReducer, {
isLoading: false,
isError: false,
data: initialData,
});
const [url, setUrl] = useState(initialUrl);


const [state, dispatch] = useReducer(dataFetchReducer, {
isLoading: false,
isError: false,
data: initialData,
});
//getData //getData
useEffect(() => { useEffect(() => {
const fetchData = async () => { const fetchData = async () => {
}, [url]); }, [url]);


return [state, setUrl];
};
useEffect(() => {
let didCancel = false;

const fetchData = async () => {
dispatch({ type: 'FETCH_INIT' });

try {
const result = await axios(url);

if (!didCancel) {
dispatch({ type: 'FETCH_SUCCESS', payload: result.data.data.attributes });
}
} catch (error) {
if (!didCancel) {
dispatch({ type: 'FETCH_FAILURE' });
}
}
};

fetchData();

return () => {
didCancel = true;
};
}, [url]);

return [state, setUrl];
};


export default useDataApi;
export default useDataApi

+ 21
- 0
frontend/src/hooks/useHoverOutside.js Просмотреть файл

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

export default function useHoverOutside(initialIsVisible) {
const [show, setShow] = useState(initialIsVisible);
const ref = useRef(null);

const handleHoverOutside = (event) => {
if (ref.current && !ref.current.contains(event.target)) {
setShow(false);
}
};

useEffect(() => {
document.addEventListener('mouseover', handleHoverOutside, true);
return () => {
document.removeEventListener('mouseover', handleHoverOutside, true);
};
}, []);

return { ref, show, setShow };
}

+ 5
- 0
frontend/src/index.css Просмотреть файл

monospace; monospace;
} }


.no-scroll::-webkit-scrollbar {
width: 0;
background: transparent;
}

@import "./styles/import.styles.css"; @import "./styles/import.styles.css";

+ 5
- 1
frontend/src/index.js Просмотреть файл

import { CookiesProvider } from 'react-cookie'; import { CookiesProvider } from 'react-cookie';
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom';
import { HelmetProvider } from 'react-helmet-async'; import { HelmetProvider } from 'react-helmet-async';
import { UIContext } from './context/index';


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


<BrowserRouter> <BrowserRouter>
<CookiesProvider> <CookiesProvider>
<HelmetProvider> <HelmetProvider>
<App />
<UIContext.Provider value={UIContext} >
<App />
</UIContext.Provider>
</HelmetProvider> </HelmetProvider>
</CookiesProvider> </CookiesProvider>
</BrowserRouter> </BrowserRouter>

+ 1
- 1
frontend/src/layout/Wrapper.jsx Просмотреть файл



const Wrapper = ({bg, padding ,children, hideOverflow}) => { const Wrapper = ({bg, padding ,children, hideOverflow}) => {
return ( return (
<div className={(bg ? "bg-baby-blue dark:bg-dg-primary-1600 h-fit" : "")+(padding)+(hideOverflow ? ' overflow-hidden' : '')}>
<div className={"w-full " + (bg ? "bg-baby-blue dark:bg-dg-primary-1600 h-fit" : "")+(padding)+(hideOverflow ? ' overflow-hidden' : '')}>
<div className="max-w-custom relative mx-auto px-16p"> <div className="max-w-custom relative mx-auto px-16p">
{children} {children}
</div> </div>

+ 233
- 374
frontend/src/pages/About.jsx Просмотреть файл

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

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


import Animation_Diligent from '../assets/animation_diligent.webm'; import Animation_Diligent from '../assets/animation_diligent.webm';
import HighlighedText from '../components/shared/HighlighedText'; import HighlighedText from '../components/shared/HighlighedText';


import NisExpress from '../assets/NE_large_logo.png'; import NisExpress from '../assets/NE_large_logo.png';


import Djole from './../';
import valuesBG from './../assets/ValuesBG.svg'; import valuesBG from './../assets/ValuesBG.svg';
import TimelineCardsWrapper from '../components/TimelineWrapper';
import TimelineCard from '../components/TimelineCard'; import TimelineCard from '../components/TimelineCard';
import PageTitle from '../components/shared/PageTitle'; import PageTitle from '../components/shared/PageTitle';
import Wrapper from '../layout/Wrapper'; import Wrapper from '../layout/Wrapper';
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'; import ReactHelmet from '../components/shared/ReactHelmet';

const _data = {
heading: {
subheading: 'About Us',
heading: 'Who We Are',
imgUrl:
'https://lh4.googleusercontent.com/4AxnSLGq46gLcFyYdz1508l45FIeIhlsrb02v-AnNenATYLG15qFgIl3pbBfjHVg1nY=w2400',
paragraph:
'When ten enthusiasts came together in 2020 with the same vision and impactful goals our journey officially began. We believed that taking small steps could result in meaningful changes and help us succeed in areas of a global pandemic and rapid social changes.',
},
segment1: {
paragraph:
'Diligent Software is a collaborative software development team that delivers high-quality custom software solutions while also cultivating a work environment that promotes community, family, learning, and mentoring.',
imgUrl:
'https://lh5.googleusercontent.com/YD0JCH9v2hZ2_M42T7QD4U1CbTPolaelasj0SJF8kDQQiuRFmO9lLukjxfBqg5dxHsY=w2400',
},
segment2: {
paragraph:
'By utilizing cutting-edge technologies, our agile, multi-disciplinary teams provide a combination of product & technology strategies, intelligent experiences, and world-class engineering to help our clients become more engaging, responsive, and efficient.',
imgUrl:
'https://lh6.googleusercontent.com/WEoQNbjwT9EpeG2kM4pvdeJM4MwFoEnSj2Dn0e3vPM54iN6P911_Y0wAXvSsbspd3Lg=w2400',
},
subtitle: 'Diligent has close to 100 employees located throughout Serbia.',
subtitleImgUrl:
'https://lh5.googleusercontent.com/Nk7pWU1H028YvdMkXvH6CECmQVWtTuKpKQuTUTKzUVXfhCF1JAjXThy1585YnXYdWio=w2400',
italicParagraph:
'We understand that investing in long-term customer relationships is essential, but we also recognize the importance of providing rewarding and challenging careers for our employees.',
segment3: {
mission: {
title: 'Our Vision',
imgUrl:
'https://lh5.googleusercontent.com/IdGSbzSZ8fRwwkP43Lkzm3fQBRGqywFNpfi2Qe2bkstNXunQGM1zVFrdX4blaiSGuEM=w2400',
paragraphs: [
{
paragraph:
'Our vision is to be a leading software solutions company for a variety of industries. We believe that our growth is directly related to the success of our customers, so we are dedicated to helping them achieve their business goals. ',
},
{
paragraph:
'We want to be known as a reliable, innovative, and top-quality software service provider in the IT industry. We are constantly striving to exceed the expectations of our customers and to be the best in our field. ',
},
],
},
vision: {
title: 'Our Mission',
imgUrl:
'https://lh3.googleusercontent.com/gqO6y406jsrU5mt2c2rcbZS-2Z6Q9rg2zxHQ576LExMo1ptRx-SVZj2iAkR1wg2lNF0=w2400',
paragraphs: [
{
paragraph:
'Our mission is to help our customers grow their businesses through creative design and development solutions. We strive to deliver market-defining high-quality solutions that create value and competitive advantage for our customers around the world.',
},
{
paragraph:
'We are dedicated to providing our clients with the best possible service and continually improving our processes and capabilities to better meet their needs. ',
},
],
},
},
values: {
heading: 'Values',
cards: [
{
id: 0,
iconUrl: Care,
title: 'Care',
paragraph:
'We believe that by working together and being kind to one another, we can make a difference. We care about work colleagues, ourselves, partnerships, but also the planet. We constantly strive to be helpful, kind, and inclusive in everything we do and looking for ways to be more sustainable. ',
},
{
id: 1,
iconUrl: Culture,
title: 'Culture',
paragraph:
'Our people love what they do. We provide a fun and supportive environment that empowers our staff to grow, learn, and thrive. We are consistent and transparent in our actions and committed to our clients and colleagues. We believe that together we can achieve more.',
},
{
id: 2,
iconUrl: Doing,
title: 'Learn by Doing',
paragraph:
'Our legacy is our impact on the people around us. By being kind and helping others, we can make a positive difference and leave a lasting impression. We grow as individuals, as well as we grow as a team.',
},
{
id: 3,
iconUrl: Ideas,
title: 'Ideas Over Hierarchy',
paragraph:
'We believe that the best ideas can come from anywhere, both inside and outside our company. Our job is to seek out those ideas, shape and improve them through candid debate, and take them from concept to action.',
},
],
},

partners: {
title: 'Partners',
paragraph:
"We collaborate with Fortune 500 companies, innovative start-ups, and established industry leaders. We deliver specialized software solutions and services that enable businesses to expand and face tomorrow's problems by combining world-class engineering teams, sector knowledge, and technical experts.",
icons: [
'https://lh4.googleusercontent.com/e5Zf5H4bL-6N4R7TOJIlB7hAPzzIk41dnWlCvJDZKAWyyjbJ_kWmONzHqddi11rb_SA=w2400',
'https://lh6.googleusercontent.com/4QxTBdL0JdRHjbujuHSEO9ysyQL7N64bykQm4DutzoAB0MOIYBODgShJ9uSChiI1kHo=w2400',
NisExpress,
'https://lh6.googleusercontent.com/8TrErMJ6QyxdwhmM57Oiy-41Db7thyvaHmGfb4teaFiYKWFVDd3reL1Ok1T88nAgvaE=w2400',
'https://lh4.googleusercontent.com/D05_HBhHcJf8Rpbxf7Uc4ix_J4advqIFM6Rwe-Vd9huTQCt2JKocAKqAf_AwszThr2Y=w2400',
],
},
industries: {
title: 'Industries',
industries: [
{
title: 'Fintech',
paragraph:
'We help fintech startups and financial institutions to manage risk and stay ahead of the curve by developing financial software solutions and integrating them with third-party systems while ensuring the stable operation of financial systems.',
imgUrl:
'https://lh6.googleusercontent.com/hNzi8UOWwAYzL9ZFR5bPnhge1RCIPgaFDwvZ-Cz7jaIRzKOySxZi2duV5-plTpGczLE=w2400',
},
{
title: 'Healthcare',
paragraph:
'We provide the healthcare sector with seamless transitions from an offline business to a tailored digital platform. All with the assistance of cutting-edge technology to enhance the user experience and improve health care delivery.',
imgUrl:
'https://lh4.googleusercontent.com/8xQPhJ2FZrTFamSUf2EkpL_vsvjAFymUEEX4PWF-R4Mhznt6vo2kkYCHY4gZCF5XjYs=w2400',
},
],
},
timeline: {
subtitle: 'our journey',
title: 'Timeline of Our Growth',
cards: [
{
subtitle: '1st Step',
title: 'First Year of Our Work',
paragraph:
'Our journey began two years ago when a group of ten tech enthusiasts made the decision to put their ideas into practice and accomplish their goals. With more than ten years of technology experience in a variety of industries, including fintech, transportation, and healthcare, they created a modern company that can deliver solutions tailored to each client. ',
},
{
subtitle: '2nd Step',
title: 'Choosing our clients',
paragraph:
'We strive to build strong partnerships with our clients. We can proudly say that our biggest value is a long-lasting partnership with our very first clients. Good impressions and commitment lead us to the first clients. Furthermore, we continue to build long-term partnerships. ',
},
{
subtitle: '3rd Step',
title: 'Overcoming hard times',
paragraph:
'As the COVID-19 pandemic was taking off, we were extremely impressed by how well our team adapted to the changing circumstances. Diligent’s greatest strengths have always been our team of highly qualified and experienced professionals. Diligent team increased from 35 employees to 67 technology experts.',
},
{
subtitle: '4th Step',
title: 'Where We Are Today',
paragraph:
'We are constantly growing, coding the vision of the future! Today we are about to have 100 employees who diligently work on more than 50 projects, trying to give cutting-edge solutions to the most common and modern problems. Our partnerships with the clients are based on trust and commitment.',
},
{
subtitle: '5th Step',
title: 'road to future success',
paragraph:
'Professional and personal growth and development of our employees are crucial for strengthening our team. We strive hard to offer high-quality education, mentoring, and an inspiring environment where everyone may reach their full potential. This will enable us to progress as a team and achieve our long-term goals.',
},
],
},
};
import { strapiApiBuilder } from './../utils/strapiApiBuilder';
import useDataApi from './../hooks/useDataApi';


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


const strapiPopulate = [
'Heading.Image',
'Section.Image',
'ItalicSection.Section.Image',
'Mission.Image',
'Vision.Image',
'Values.Items',
'Values.Items.Image',
'Partners.images',
'Indrustries',
'Industries.Items',
'Industries.Items.Image',
'TimelineHeading',
'Timeline.Steps',
'SEO.metaSocial',
'SEO.metaImage',
'SEO.metaSocial.image',
];

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


useEffect(async () => {
const [{ data, isLoading, isError }, doFetch] = useDataApi(strapi);

useAnalytics('About page');

useEffect(() => {
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('About Us');

if (!isLoaded) {
if (isLoading) {
return ( 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"> <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> <video id="animation" width="540" height="540" autoPlay muted loop>


return ( return (
<PageLayout> <PageLayout>
{cnt.SEO && <ReactHelmet seo={cnt.SEO} />}
{(data && data.SEO) ? <ReactHelmet seo={data.SEO} /> : null}
<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
id="heading"
className="flex flex-col items-center justify-center max-w-custom m-auto"
>
<div className="mb-8 flex flex-col md:flex-row gap-4 lg-gap-0 justify-start items-start w-full px-8 xl:px-0">
<div className="w-full md:w-1/2 md:pr-16">
<h6 className="subheading">{_data.heading.subheading}</h6>
<h1 className="heading text-dg-secondary mt-2">{_data.heading.heading}</h1>
<p className="paragraph mt-4">{_data.heading.paragraph}</p>
</div>
<img
src={_data.heading.imgUrl}
alt="Our Team's image"
className="w-full md:w-1/2 text-center -ml-2 lg-ml-0"
/>
</div>
</section>

{/* The After Heading pt.1 Section */}
<section
id="after_heading"
className="bg-white dark:bg-dg-primary-1700 flex items-center justify-center px-2"
>
<div className="my-8 flex flex-col-reverse md:flex-row justify-center items-center max-w-custom m-auto w-full px-8 xl:px-0">
<img
src={_data.segment1.imgUrl}
alt="Our Team's image"
className="w-full md:w-1/2 text-center mt-8 md:mt-0"
/>
<div className="w-full md:w-1/2 md:pl-16">
<p className="paragraph mt-4">{_data.segment1.paragraph}</p>
</div>
</div>
</section>
{data ? (
<section
id="heading"
className="flex flex-col items-center justify-center max-w-custom m-auto w-full"
>
<Wrapper>
<div className="flex flex-col md:flex-row gap-8p w-full">
<div className="w-full md:w-1/2">
<PageTitle
heading={data.Heading.Title}
subheading={data.Heading.Subtitle}
left
color
/>
<p className="mt-4 paragraph">{data.Heading.Paragraph}</p>
</div>
<img
src={api_url + data.Heading.Image.data.attributes.url}
alt="Our Team's image"
className="w-full md:w-1/2 text-center -ml-2 lg-ml-0"
/>
</div>
</Wrapper>
</section>
) : null}


{/* The After Heading pt.2 Section */}
<section id="after_heading" className="flex flex-col items-center justify-center">
<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">
<p className="paragraph mt-4">{_data.segment2.paragraph}</p>
</div>
<img
src={_data.segment2.imgUrl}
alt="Office's image"
className="w-full md:w-1/2 text-center"
/>
</div>
</section>
{data ? (
<section
id="sections"
className="flex flex-col items-center justify-center max-w-custom m-auto w-full"
>
{data.Section.map((item, index) => (
<div key={index}>
<Wrapper>
<div
className={
'flex flex-col gap-8 w-full items-center' +
(index % 2 == 0 ? ' md:flex-row-reverse' : ' md:flex-row')
}
>
<p className="mt-4 paragraph w-full md:w-1/2">{item.Paragraph}</p>
<img
src={api_url + item.Image.data.attributes.url}
alt="Our Team's image"
className="w-full md:w-1/2 text-center -ml-2 lg-ml-0"
/>
</div>
</Wrapper>
</div>
))}
</section>
) : null}


{/* Highlighted Text Section */}
<section
id="highlight"
className="flex flex-col items-center justify-center mt-16"
>
<HighlighedText text={_data.subtitle} />
</section>
{data ? (
<>
<section
id="highlight"
className="flex flex-col items-center justify-center mt-16"
>
<HighlighedText text={data.ItalicSection.Italic} />
</section>


{/* Info Section */}
<section id="info" className="flex flex-col items-center justify-center mt-16">
<div className="flex flex-col items-center justify-center w-full">
<img
src={_data.subtitleImgUrl}
alt="Info image"
className="max-w-[660px] w-full"
/>
<p className="text-sm font-medium italic text-gray-500 dark:text-white w-2/3 lg:w-1/3 mt-4">
{_data.italicParagraph}
</p>
</div>
</section>
<section
id="info"
className="flex flex-col items-center justify-center mt-16"
>
<div className="flex flex-col items-center justify-center w-full">
<img
src={api_url + data.ItalicSection.Section.Image.data.attributes.url}
alt={
api_url +
data.ItalicSection.Section.Image.data.attributes.alternativeText
}
className="max-w-[660px] w-full"
/>
<p className="text-sm font-medium italic text-gray-500 dark:text-white w-2/3 lg:w-1/3 mt-4">
{data.ItalicSection.Section.Paragraph}
</p>
</div>
</section>
</>
) : null}


{/* Our Mission & Our Vision Section */} {/* Our Mission & Our Vision Section */}
<section
id="mission_vision"
className="bg-baby-blue dark:bg-dg-primary-1600 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">
<h2 className="heading text-dg-secondary">{_data.segment3.vision.title}</h2>
{_data.segment3.vision.paragraphs.map((item, index) => (
<p key={index} className="paragraph mt-4">
{item.paragraph}
</p>
))}
{data ? (
<section
id="mission_vision"
className="bg-baby-blue dark:bg-dg-primary-1600 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">
<h2 className="heading text-dg-secondary">{data.OurMission}</h2>
<p className="paragraph mt-4">{data.Mission.Paragraph}</p>
</div>
<img
src={api_url + data.Mission.Image.data.attributes.url}
alt={api_url + data.Mission.Image.data.attributes.alternativeText}
className="text-center w-full md:w-1/2"
/>
</div> </div>
<img
src={_data.segment3.mission.imgUrl}
alt="Our mission image"
className="text-center w-full md:w-1/2"
/>
</div>
<div className="my-8 flex flex-col-reverse md:flex-row justify-center items-center w-full max-w-custom m-auto px-8 xl:px-0">
<img
src={_data.segment3.vision.imgUrl}
alt="Our vision image"
className="text-center w-full md:w-1/2 mt-8 md:mt-0"
/>
<div className="w-full md:w-1/2 md:pl-16">
<h2 className="heading text-dg-secondary">
{_data.segment3.mission.title}
</h2>
{_data.segment3.mission.paragraphs.map((item, index) => (
<p key={index} className="paragraph mt-4">
{item.paragraph}
</p>
))}
<div className="my-8 flex flex-col-reverse md:flex-row justify-center items-center w-full max-w-custom m-auto px-8 xl:px-0">
<img
src={api_url + data.Vision.Image.data.attributes.url}
alt={api_url + data.Vision.Image.data.attributes.alternativeText}
className="text-center w-full md:w-1/2 mt-8 md:mt-0"
/>
<div className="w-full md:w-1/2 md:pl-16">
<h2 className="heading text-dg-secondary">{data.OurVision}</h2>
<p className="paragraph mt-4">{data.Vision.Paragraph}</p>
</div>
</div> </div>
</div>
</section>
</section>
) : null}


{/* Values Section */} {/* Values Section */}
<section
id="values"
className="bg-white dark:bg-dg-primary-1700 flex flex-row items-center justify-center mt-16"
>
<div className="my-8 flex flex-col justify-center items-start w-full max-w-custom m-auto px-8 xl:px-0">
<h2 className="heading text-dg-secondary">{_data.values.heading}</h2>
<div className="absolute justify-center md:flex hidden self-center">
<img src={valuesBG} alt="Values background" />
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-16 w-full mt-8">
{_data.values.cards.map((item, index) => (
<CardValues
key={index}
image={item.iconUrl}
heading={item.title}
paragraph={item.paragraph}
/>
))}
{data ? (
<section
id="values"
className="bg-white dark:bg-dg-primary-1700 flex flex-row items-center justify-center mt-16"
>
<div className="my-8 flex flex-col justify-center items-start w-full max-w-custom m-auto px-8 xl:px-0">
<h2 className="heading text-dg-secondary">{data.Values.Title}</h2>
<div className="absolute justify-center md:flex hidden self-center">
<img src={valuesBG} alt="Values background" />
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-16 w-full mt-8">
{data.Values.Items.map((item, index) => (
<CardValues
key={index}
image={api_url + item.Image.data.attributes.url}
alt={api_url + item.Image.data.attributes.alternativeText || 'alt'}
heading={item.heading}
paragraph={item.paragraph}
/>
))}
</div>
</div> </div>
</div>
</section>
</section>
) : null}


{/* Partners Section */} {/* Partners Section */}
<section
id="partners"
className="bg-baby-blue dark:bg-dg-primary-1600 flex flex-col items-center justify-center mt-16"
>
<div className="my-16 flex flex-col justify-center items-center w-full max-w-custom m-auto px-8 xl:px-0">
<div className="w-full md:w-2/3">
<h2 className="text-center heading text-dg-secondary">
{_data.partners.title}
</h2>
<p className="text-left paragraph mt-4">{_data.partners.paragraph}</p>
</div>
<div className="flex flex-row justify-between items-center w-full mt-16">
{_data.partners.icons.map((item, index) => (
<img
key={index}
src={item}
alt="Partner's image"
className="w-16 md:w-20 lg:w-24"
/>
))}
{data ? (
<section
id="partners"
className="bg-baby-blue dark:bg-dg-primary-1600 flex flex-col items-center justify-center mt-16"
>
<div className="my-16 flex flex-col justify-center items-center w-full max-w-custom m-auto px-8 xl:px-0">
<div className="w-full md:w-2/3">
<h2 className="text-center heading text-dg-secondary">
{data.Partners.heading}
</h2>
<p className="text-left paragraph mt-4">{data.Partners.paragraph}</p>
</div>
<div className="flex flex-row justify-between items-center w-full mt-16">
{data.Partners.images.data.map((item, index) => (
<img
key={index}
src={api_url + item.attributes.url}
alt={api_url + item.attributes.alternativeText}
className="w-16 md:w-20 lg:w-24"
/>
))}
</div>
</div> </div>
</div>
</section>
</section>
) : null}


{/* Industries Section */} {/* Industries Section */}
<section
id="industries"
className="bg-white dark:bg-dg-primary-1700 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">
<h2 className="heading text-dg-secondary">{_data.industries.title}</h2>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-32 w-full mt-8">
{_data.industries.industries.map((industry, index) => (
<div key={index}>
<h3 className="h3-heading">{industry.title}</h3>
<p className="paragraph mt-2">{industry.paragraph}</p>
<img src={industry.imgUrl} alt="Industries images" className="m-auto" />
</div>
))}
{data ? (
<section
id="industries"
className="bg-white dark:bg-dg-primary-1700 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">
<h2 className="heading text-dg-secondary">{data.Industries.Title}</h2>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-32 w-full mt-8">
{data.Industries.Items.map((industry, index) => (
<div key={index}>
<h3 className="h3-heading">{industry.heading}</h3>
<p className="paragraph mt-2">{industry.paragraph}</p>
<img
src={api_url + industry.Image.data.attributes.url}
alt={api_url + industry.Image.data.attributes.alternativeText}
className="m-auto"
/>
</div>
))}
</div>
</div> </div>
</div>
</section>
</section>
) : null}


<Wrapper bg padding={' py-90p'}>
<PageTitle
heading={_data.timeline.title}
subheading={_data.timeline.subtitle}
left
/>
{data ? (
<Wrapper bg padding={' py-90p'}>
<PageTitle
heading={data.TimelineHeading.title}
subheading={data.TimelineHeading.subtitle}
left
/>


<div className="my-90p">
<div className="w-full relative ">
<div className="md:absolute top-[5%] left-0 w-full h-full hidden md:block">
<TimelineLogo />
</div>
<div className="my-90p">
<div className="w-full relative ">
<div className="md:absolute top-[5%] left-0 w-full h-full hidden md:block">
<TimelineLogo />
</div>


<TimelineCardsWrapper2>
{_data.timeline.cards.map((item, index) => (
<TimelineCard
key={index}
id={index}
title={item.title}
subtitle={item.subtitle}
paragraph={item.paragraph}
/>
))}
</TimelineCardsWrapper2>
<TimelineCardsWrapper2>
{data.Timeline.Steps.map((item, index) => (
<TimelineCard
key={index}
id={index}
title={item.heading}
subtitle={item.subheading}
paragraph={item.paragraph}
/>
))}
</TimelineCardsWrapper2>
</div>
</div> </div>
</div>
</Wrapper>
</Wrapper>
) : null}
</div> </div>
</PageLayout> </PageLayout>
); );

+ 214
- 199
frontend/src/pages/Careers.jsx Просмотреть файл

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


import ImgStep1 from '../assets/images/CaseStudy/CentralizedSmall.png';
import ImgStep2 from '../assets/images/Careers/events.png';
import ImgStep3 from '../assets/images/CaseStudy/CentralizedSmall.png';
import ImgStep4 from '../assets/images/Careers/events.png';
import ImgStep5 from '../assets/images/CaseStudy/CentralizedSmall.png';
import ImgEvents from '../assets/images/Careers/events.png';

import Care from './../assets/icons/values/care.svg';
import Doing from './../assets/icons/values/doing.svg';
import Culture from './../assets/icons/values/culture.svg';
import Ideas from './../assets/icons/values/ideas.svg';

import CardsGrid from '../components/CardsGrid';

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 CardCareers2 from '../components/CareerCardsTemplates/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 TimelineCard from '../components/TimelineCard';

import { useNavigate } from 'react-router-dom';
import useAnalytics from './../hooks/useAnalytics';
import HRProcess from '../components/HRProcess';
import VideoComponent from './../components/shared/VideoComponent';
import { strapiApiBuilder } from './../utils/strapiApiBuilder';
import useDataApi from './../hooks/useDataApi';
import ReactHelmet from './../components/shared/ReactHelmet';

const api_url = process.env.REACT_APP_API_URL;

const strapiPopulate = [
'diligent_life',
'diligent_life.heading_section',
'diligent_life.CTO',
'diligent_life.media_text.media',
'selection_process.heading',
'selection_process.steps.media',
'positions_heading',
'positions_card.Image',
'benefits_heading',
'benefits_card.media',
'Cards.Card3.Image',
'ActionCard',
'Video',
'SEO',
'SEO.metaSocial',
'SEO.metaImage',
'SEO.metaSocial.image',
];


// eslint-disable-next-line no-underscore-dangle // eslint-disable-next-line no-underscore-dangle
const _data = { const _data = {
heading: {
heading: 'Join Our Team of Diligent Minds',
subheading: 'Careers',
},
job: { job: {
NetDev: { NetDev: {
id: 1, id: 1,
'Private health insurance', '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: {
heading: 'A Culture That’s Serious About Work and Fun',
subheading: 'Diligent life',
italic: {
heading: 'Life At diligent',
paragraph:
'From the start, you can expect to be challenged and supported. We provide a encouraged atmosphere with knowledgeable mentors to help you advance in your career. To create an inspiring work life, we collaborate as a team both inside and outside of the office.',
heading2: 'What It Means to Work With Us',
}, },
cards: [
{
id: 1,
title: 'Shape the Future',
paragraph:
'We collaborate with business leaders and entrepreneurs to disrupt and push their industries forward. From startup ideas to enterprise-level product & software development, we work together as a team to transform our clients’ ideas into reality.',
},
{
id: 2,
title: 'Life-Long Learning',
paragraph:
'We believe that learning is a journey that never ends. With us, you will have the opportunity to continuously learn in an environment surrounded by other highly skilled professionals with decades of experience. Also, there are several chances for you to develop through the use of various technologies, involvement in the product definition process, conference attendance, and more.',
},
{
id: 3,
title: 'A Unique Culture',
paragraph:
'Everyone talks about a work-life balance, we do it - for two reasons. Firstly, we believe in an environment of happy people. Secondly, even if you’re highly productive, the only way to maintain productivity long-term is by taking time for the things that make you happy.',
},
{
id: 4,
title: 'Make the Impossible Better',
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: paragraph:
"If you have a mindset that is continuously focused on pushing through and beyond your boundaries, conquering a whole new challenge every day in an atmosphere where you constantly learn and improve, this is the place for you. We'd love to learn more about you.",
'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.',
}, },
],
},
connect: {
heading: 'Connect and Grow With Us',
paragraph:
'At Diligent, we are passionately proud of our culture and feel that everyone, including those who are not yet on the team, should have the opportunity to experience it. Because of this, we participate in Open Doors. Our coworkers are actively involved in the local tech communities. We take satisfaction in giving back as well, assisting college students or seasoned professionals who want to start a career in IT.',
subtitle: 'Check out how we have fun together!',
sliderImages: [],
},
ActionCard: {
heading: 'Contact Us and Step up Your Career!',
paragraph:
'We are continuously on the lookout for talented people to grow our business.',
paragraph2: "Don't be shy - Apply!",
primaryBtn: 'Apply',
secondaryBtn: 'About Us',
},
}, },
cards: [
{
id: 0,
title: 'BI Healthcare Solution System',
imgUrl:
'https://lh6.googleusercontent.com/D7N87i3udAln4YBp5SbaSI-9r2pVnnT5K2VT6p0G3dQanVgTMC2tdgz71PWOYco-7yQ=w2400',
alt: 'BI Healthcare Solution System',
link: '/casestudybi',
},
{
id: 1,
title: 'Resource Planning System',
imgUrl:
'https://lh5.googleusercontent.com/HLOh5coHfcEgDuftj1pOA9f1865xiIom5vyxTWNMKqMiivxL8Lg4c9ACzbfYYUdeuqQ=w2400',
alt: 'Resource Planning System',
link: '/casestudyresource',
},
{
id: 2,
title: 'Ticketing System for Passengers',
imgUrl:
'https://lh5.googleusercontent.com/f_G0H0C_qLHhsU8PBj6uTkNigzKiXzd24B_pgJ6UqVmBKlU2Lyxv2r5lf6uvY9d_0PY=w2400',
alt: 'Ticketing System for Passengers',
link: '/casestudyticketing',
},
],
}; };


export default function Careers({ forwardedRef }) { export default function Careers({ forwardedRef }) {
const [clickedPosition, setClickedPosition] = useState(''); const [clickedPosition, setClickedPosition] = useState('');
const [cntCareers, setCntCareers] = useState('');
const [isLoaded, setIsLoaded] = useState('');


const api_url = process.env.REACT_APP_API_URL;
const strapi = strapiApiBuilder('n-careerspage', strapiPopulate);

const [{ data, isLoading, isError }, doFetch] = useDataApi(strapi);

//console.log(data);


useEffect(() => { useEffect(() => {
document.title = 'Careers'; document.title = 'Careers';


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


useEffect(async () => {
var vid = document.getElementById('animation');
vid.playbackRate = 2;
axios
.get(
`${api_url}/api/careerspage?populate[0]=heading&populate[1]=info&populate[2]=job.icon`,
)
.then(res => {
//console.log(res.data.data.attributes);
setCntCareers(res.data.data.attributes);
setIsLoaded(true);
})
.catch(err => {
console.log(err);
setIsLoaded(false);
});
}, []);
const link = useNavigate();


if (!isLoaded) {
//useEffect(() => { vidRef.current.play(); },[]);

if (isLoading) {
return ( 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"> <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> <video id="animation" width="540" height="540" autoPlay muted loop>


return ( return (
<PageLayout> <PageLayout>
<div className="bg-white dark:bg-dg-primary-1700 w-full pt-90p overflow-hidden">
<Wrapper padding={' py-90p'}>
<h1 className="hidden">Careers - Join our Team</h1>
<PageTitle
heading={_data.heading.heading}
subheading={_data.heading.subheading}
left
color
/>
</Wrapper>
<Wrapper padding={' py-90p'}>
<div className="absolute hidden -ml-64 md:block">
<OrbitOnScroll />
</div>
<section
id="jobs"
className="flex items-center justify-center max-w-custom m-auto"
>
<div className="w-full">
<CardCareers2 cards={_data.job} />
{data ? (
<div className="bg-white dark:bg-dg-primary-1700 w-full md:pt-90p overflow-hidden">
{data.SEO ? <ReactHelmet seo={data.SEO} /> : null}
{/* Diligent Life */}
<Wrapper padding={' py-90p'}>
<PageTitle
left
heading={data.diligent_life.heading_section.heading}
subheading={data.diligent_life.heading_section.subheading}
/>

<div className="mt-20p">
<div>
<p className="paragraph">
{data.diligent_life.heading_section.paragraph}
</p>

{/* Video Frame */}
{data && data.Video != undefined ? (
<VideoComponent source={data.Video.data.attributes.url} alt={data.Video.data.attributes.alternativeText} />
) : null}
</div>
</div>

<div className="flex flex-col md:flex-row items-center justify-between lg:justify-center gap-8">
<p className="paragraph w-full lg:w-3/4">
{data.diligent_life.CTO.cto_paragraph}
</p>
{/* Disabled becouse no content on that page */}
{/* <button
className="btn-secondary min-w-fit"
onClick={() => link('/diligentlife')}
>
{data.diligent_life.CTO.cto_button}
</button> */}
</div> </div>
</section>
</Wrapper>
<div className='mt-90p'>
<Wrapper bg padding={' py-90p'}>
<PageTitle
left
heading={_data.life.heading}
subheading={_data.life.subheading}
/>
</Wrapper>

{/* Selection Process */}
<Wrapper bg padding={' py-90p'}>
<PageTitle
left
heading={data.selection_process.heading.heading}
subheading={data.selection_process.heading.subheading}
/>
<HRProcess data={data} />
</Wrapper>


<div className="my-90p">
<div className="my-90p">
<h3 className="title-italic">{_data.life.italic.heading}</h3>
<p className="paragraph">{_data.life.italic.paragraph}</p>
<div className="w-full py-90p">
<iframe
className="m-auto w-[300px] h-[180px] md:w-[500px] md:h-[400px] lg:w-[800px] lg:h-[560px]"
src="https://www.youtube.com/embed/PFHIqqHRS4s?controls=0"
title="YouTube video player"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
></iframe>
{/* Open Positions */}
<Wrapper padding={' py-90p'}>
<PageTitle
heading={data.positions_heading.heading}
subheading={data.positions_heading.subheading}
left
color
/>
<div className="pt-72p">
<div className="absolute hidden -ml-64 md:block">
<OrbitOnScroll />
</div> </div>
<section
id="jobs"
className="flex items-center justify-center max-w-custom m-auto"
>
<div className="w-full">
<CardCareers2 cards={_data.job} />
</div>
</section>
</div> </div>
<h3 className="title-italic">{_data.life.italic.heading2}</h3>
</div>
</Wrapper>


<div className="">
<section
id="life"
className="dark:bg-dg-primary-1700 flex flex-row items-center justify-center"
>
<div className="flex flex-col justify-center items-start w-full max-w-custom m-auto px-8 xl:px-0">
<div className="grid grid-cols-1 md:grid-cols-2 gap-16 w-full">
{_data.life.cards.map((item, index) => (
<CardLife
{/* Benefits Section */}
<Wrapper bg padding={' py-90p'}>
<section id="values" className="flex flex-row items-center justify-center">
<div className="my-8 flex flex-col justify-center items-start w-full max-w-custom m-auto">
<h2 className="heading text-dg-secondary">
{data.benefits_heading.heading}
</h2>
<div className="grid grid-cols-1 gap-16 w-full mt-8">
{data.benefits_card.map((item, index) => (
<CardValues
key={index} key={index}
number={item.id}
heading={item.title}
image={api_url + item.media.data.attributes.url}
heading={item.heading}
paragraph={item.paragraph} paragraph={item.paragraph}
/> />
))} ))}
</div> </div>
</div> </div>
</section> </section>
</div>
</Wrapper>
</Wrapper>

{/* Action Card */}
{data ? (
<Wrapper>
<div className="my-90p">
<ActionCard
title={data.ActionCard.title}
text={data.ActionCard.paragraph}
btn1={data.ActionCard.ButtonPrimary}
btn2={data.ActionCard.ButtonSecondary}
link1={'/contact'}
link2={'/about'}
/>
</div>
</Wrapper>
) : null}
</div> </div>
<Wrapper padding={' py-90p'}>
<PageTitle heading={_data.connect.heading} color />
<p className="paragraph my-32p">{_data.connect.paragraph}</p>
</Wrapper>
<Wrapper>
<section id="highlight" className="flex flex-col items-center justify-center">
<HighlighedText text={_data.connect.subtitle} />
</section>
</Wrapper>
<Wrapper>
<AboutUsSlider />
</Wrapper>
<Wrapper>
<div className="my-90p">
<ActionCard
title={_data.ActionCard.heading}
text={_data.ActionCard.paragraph}
btn1={_data.ActionCard.primaryBtn}
btn2={_data.ActionCard.secondaryBtn}
link1={'/contact'}
link2={'/about'}
text2={_data.ActionCard.paragraph2}
/>
</div>
</Wrapper>
</div>
) : null}
</PageLayout> </PageLayout>
); );
} }

+ 32
- 8
frontend/src/pages/ContactPage.jsx Просмотреть файл

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

const api_url = process.env.REACT_APP_API_URL;

const strapiPopulate = [
'BusinessInquiry',
'BusinessInquiry.image',
'ApplyPosition',
'ApplyPosition.image',
'SEO',
'SEO.metaSocial',
'SEO.metaImage',
'SEO.metaSocial.image',
];

function ContactPage({tab, position}) {

const strapi = strapiApiBuilder('w-home-page', strapiPopulate);

const [{ data, isLoading, isError }, doFetch] = useDataApi(strapi);


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


useEffect(() => { useEffect(() => {
document.title = 'Contact Us'; document.title = 'Contact Us';


return ( return (
<PageLayout> <PageLayout>
{/* {data.SEO ? <ReactHelmet seo={data.SEO} /> : null} */}
<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>
<UIContext.Provider value={UIContext}>
<Contact />
</UIContext.Provider>
{data ?
<Contact
defaultIndex={tab}
position={position || ''}
job={data.ApplyPosition}
business={data.BusinessInquiry}
/> : null
}
</section> </section>
</PageLayout> </PageLayout>
); );

+ 247
- 0
frontend/src/pages/DiligentLife.jsx Просмотреть файл

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

import Img1 from '../assets/images/Careers/img1.png';
import Img2 from '../assets/images/Careers/img2.png';
import Img3 from '../assets/images/Careers/img3.png';
import Img4 from '../assets/images/Careers/img4.png';

import CardsGrid from '../components/CardsGrid';

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

// eslint-disable-next-line no-underscore-dangle
const _data = {
heading: {
heading: 'Join Our Team of Diligent Minds',
subheading: 'Careers',
},
life: {
heading: 'A Culture That’s Serious About Work and Fun',
subheading: 'Diligent life',
italic: {
heading: 'Life At diligent',
paragraph:
'From the start, you can expect to be challenged and supported. We provide a encouraged atmosphere with knowledgeable mentors to help you advance in your career. To create an inspiring work life, we collaborate as a team both inside and outside of the office.',
heading2: 'What It Means to Work With Us',
},
cards: [
{
id: 1,
title: 'Shape the Future',
paragraph:
'We collaborate with business leaders and entrepreneurs to disrupt and push their industries forward. From startup ideas to enterprise-level product & software development, we work together as a team to transform our clients’ ideas into reality.',
},
{
id: 2,
title: 'Life-Long Learning',
paragraph:
'We believe that learning is a journey that never ends. With us, you will have the opportunity to continuously learn in an environment surrounded by other highly skilled professionals with decades of experience. Also, there are several chances for you to develop through the use of various technologies, involvement in the product definition process, conference attendance, and more.',
},
{
id: 3,
title: 'A Unique Culture',
paragraph:
'Everyone talks about a work-life balance, we do it - for two reasons. Firstly, we believe in an environment of happy people. Secondly, even if you’re highly productive, the only way to maintain productivity long-term is by taking time for the things that make you happy.',
},
{
id: 4,
title: 'Make the Impossible Better',
paragraph:
"If you have a mindset that is continuously focused on pushing through and beyond your boundaries, conquering a whole new challenge every day in an atmosphere where you constantly learn and improve, this is the place for you. We'd love to learn more about you.",
},
],
},
ActionCard: {
heading: 'Step up Your Career!',
paragraph:
'We are continuously on the lookout for talented people to grow our business.',
primaryBtn: 'Apply',
secondaryBtn: 'About Us',
},
};

export default function Careers({ forwardedRef }) {
const [clickedPosition, setClickedPosition] = useState('');
const [cntCareers, setCntCareers] = useState('');
const [isLoaded, setIsLoaded] = useState('');

const api_url = process.env.REACT_APP_API_URL;

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

//useAnalytics();

useEffect(async () => {
var vid = document.getElementById('animation');
vid.playbackRate = 2;
axios
.get(
`${api_url}/api/n-careerspage?populate[0]=heading&populate[1]=info&populate[2]=job.icon&populate[3]=Video`,
)
.then(res => {
setCntCareers(res.data.data.attributes);
setIsLoaded(true);
})
.catch(err => {
console.log(err);
setIsLoaded(false);
});
}, []);

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 (
<PageLayout>
<div className="bg-white dark:bg-dg-primary-1700 w-full pt-90p overflow-hidden">
{/* Diligent Life */}
<Wrapper padding={' py-90p'}>
<PageTitle
left
heading={_data.life.heading}
subheading={_data.life.subheading}
/>

<div className="my-20p">
<div>
<p className="paragraph">{_data.life.italic.paragraph}</p>
{cntCareers && cntCareers.Video != undefined ? (
<VideoComponent source={cntCareers.Video.data.attributes.url} />
) : null}
</div>
</div>
</Wrapper>

{/* Left-Right Content */}
<Wrapper bg padding={' py-90p'}>
{/* Shape The Future */}
<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">{_data.life.cards[0].title}</h3>
<p className="text-sm text-dark-gray dark:text-white mt-4">
{_data.life.cards[0].paragraph}
</p>
</div>
</div>
<img
src={Img1}
alt="Case Study main image"
className="text-center w-full md:w-1/2"
/>
</div>
</section>

{/* Shape The Future */}
<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">
<img
src={Img2}
alt="Case Study main image"
className="text-center w-full md:w-1/2"
/>
<div className="w-full md:w-1/2 md:pl-16">
<div>
<h3 className="h3-heading">{_data.life.cards[1].title}</h3>
<p className="text-sm text-dark-gray dark:text-white mt-4">
{_data.life.cards[1].paragraph}
</p>
</div>
</div>
</div>
</section>

{/* Shape The Future */}
<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">{_data.life.cards[2].title}</h3>
<p className="text-sm text-dark-gray dark:text-white mt-4">
{_data.life.cards[2].paragraph}
</p>
</div>
</div>
<img
src={Img3}
alt="Case Study main image"
className="text-center w-full md:w-1/2"
/>
</div>
</section>

{/* Shape The Future */}
<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">
<img
src={Img4}
alt="Case Study main image"
className="text-center w-full md:w-1/2"
/>
<div className="w-full md:w-1/2 md:pl-16">
<div>
<h3 className="h3-heading">{_data.life.cards[3].title}</h3>
<p className="text-sm text-dark-gray dark:text-white mt-4">
{_data.life.cards[3].paragraph}
</p>
</div>
</div>
</div>
</section>
</Wrapper>

{/* Action Card */}
<Wrapper>
<div className="my-90p">
<ActionCard
title={_data.ActionCard.heading}
text={_data.ActionCard.paragraph}
btn1={_data.ActionCard.primaryBtn}
btn2={_data.ActionCard.secondaryBtn}
link1={'/contact'}
link2={'/about'}
/>
</div>
</Wrapper>
</div>
</PageLayout>
);
}

+ 307
- 0
frontend/src/pages/DiligentMinds.jsx Просмотреть файл

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

import ImgStep1 from '../assets/images/CaseStudy/CentralizedSmall.png';

import Care from './../assets/icons/values/care.svg';
import Doing from './../assets/icons/values/doing.svg';
import Culture from './../assets/icons/values/culture.svg';
import Ideas from './../assets/icons/values/ideas.svg';

import CardsGrid from '../components/CardsGrid';

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

// eslint-disable-next-line no-underscore-dangle
const _data = {
heading: {
heading: 'Join Our Team of Diligent Minds',
subheading: 'Careers',
},
job: {
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: {
heading: 'A Culture That’s Serious About Work and Fun',
subheading: 'Diligent life',
italic: {
heading: 'Life At diligent',
paragraph:
'From the start, you can expect to be challenged and supported. We provide a encouraged atmosphere with knowledgeable mentors to help you advance in your career. To create an inspiring work life, we collaborate as a team both inside and outside of the office.',
heading2: 'What It Means to Work With Us',
},
cards: [
{
id: 1,
title: 'Shape the Future',
paragraph:
'We collaborate with business leaders and entrepreneurs to disrupt and push their industries forward. From startup ideas to enterprise-level product & software development, we work together as a team to transform our clients’ ideas into reality.',
},
{
id: 2,
title: 'Life-Long Learning',
paragraph:
'We believe that learning is a journey that never ends. With us, you will have the opportunity to continuously learn in an environment surrounded by other highly skilled professionals with decades of experience. Also, there are several chances for you to develop through the use of various technologies, involvement in the product definition process, conference attendance, and more.',
},
{
id: 3,
title: 'A Unique Culture',
paragraph:
'Everyone talks about a work-life balance, we do it - for two reasons. Firstly, we believe in an environment of happy people. Secondly, even if you’re highly productive, the only way to maintain productivity long-term is by taking time for the things that make you happy.',
},
{
id: 4,
title: 'Make the Impossible Better',
paragraph:
"If you have a mindset that is continuously focused on pushing through and beyond your boundaries, conquering a whole new challenge every day in an atmosphere where you constantly learn and improve, this is the place for you. We'd love to learn more about you.",
},
],
},
values: {
heading: 'Values',
cards: [
{
id: 0,
iconUrl: Care,
title: 'Care',
paragraph:
'We believe that by working together and being kind to one another, we can make a difference. We care about work colleagues, ourselves, partnerships, but also the planet. We constantly strive to be helpful, kind, and inclusive in everything we do and looking for ways to be more sustainable. ',
},
{
id: 1,
iconUrl: Culture,
title: 'Culture',
paragraph:
'Our people love what they do. We provide a fun and supportive environment that empowers our staff to grow, learn, and thrive. We are consistent and transparent in our actions and committed to our clients and colleagues. We believe that together we can achieve more.',
},
{
id: 2,
iconUrl: Doing,
title: 'Learn by Doing',
paragraph:
'Our legacy is our impact on the people around us. By being kind and helping others, we can make a positive difference and leave a lasting impression. We grow as individuals, as well as we grow as a team.',
},
{
id: 3,
iconUrl: Ideas,
title: 'Ideas Over Hierarchy',
paragraph:
'We believe that the best ideas can come from anywhere, both inside and outside our company. Our job is to seek out those ideas, shape and improve them through candid debate, and take them from concept to action.',
},
],
},
cards: [
{
id: 0,
title: 'BI Healthcare Solution System',
imgUrl:
'https://lh6.googleusercontent.com/D7N87i3udAln4YBp5SbaSI-9r2pVnnT5K2VT6p0G3dQanVgTMC2tdgz71PWOYco-7yQ=w2400',
alt: 'BI Healthcare Solution System',
link: '/casestudybi',
},
{
id: 1,
title: 'Resource Planning System',
imgUrl:
'https://lh5.googleusercontent.com/HLOh5coHfcEgDuftj1pOA9f1865xiIom5vyxTWNMKqMiivxL8Lg4c9ACzbfYYUdeuqQ=w2400',
alt: 'Resource Planning System',
link: '/casestudyresource',
},
{
id: 2,
title: 'Ticketing System for Passengers',
imgUrl:
'https://lh5.googleusercontent.com/f_G0H0C_qLHhsU8PBj6uTkNigzKiXzd24B_pgJ6UqVmBKlU2Lyxv2r5lf6uvY9d_0PY=w2400',
alt: 'Ticketing System for Passengers',
link: '/casestudyticketing',
},
],
connect: {
heading: 'Connect and Grow With Us',
paragraph:
'At Diligent, we are passionately proud of our culture and feel that everyone, including those who are not yet on the team, should have the opportunity to experience it. Because of this, we participate in Open Doors. Our coworkers are actively involved in the local tech communities. We take satisfaction in giving back as well, assisting college students or seasoned professionals who want to start a career in IT.',
subtitle: 'Check out how we have fun together!',
sliderImages: [],
},
ActionCard: {
heading: 'Step up Your Career!',
paragraph:
'We are continuously on the lookout for talented people to grow our business.',
primaryBtn: 'Apply',
secondaryBtn: 'About Us',
},
};

export default function Careers({ forwardedRef }) {
const [clickedPosition, setClickedPosition] = useState('');
const [cntCareers, setCntCareers] = useState('');
const [isLoaded, setIsLoaded] = useState('');

const api_url = process.env.REACT_APP_API_URL;

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

//useAnalytics();

useEffect(async () => {
var vid = document.getElementById('animation');
vid.playbackRate = 2;
axios
.get(
`${api_url}/api/careerspage?populate[0]=heading&populate[1]=info&populate[2]=job.icon`,
)
.then(res => {
//console.log(res.data.data.attributes);
setCntCareers(res.data.data.attributes);
setIsLoaded(true);
})
.catch(err => {
console.log(err);
setIsLoaded(false);
});
}, []);

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 (
<PageLayout>
<div className="bg-white dark:bg-dg-primary-1700 w-full pt-90p overflow-hidden">
{/* Diligent Minds */}
<Wrapper padding={' py-90p'}>
<PageTitle
left
heading="Personal Development & Success Stories"
subheading="Diligent Minds"
/>
<Wrapper padding={' py-72p'}>
<CardsGrid data={_data.cards} />
</Wrapper>
<div className="flex flex-col md:flex-row items-center justify-center gap-8">
<p className="paragraph w-full md:w-1/2 lg:w-3/4">
If you have a mindset that is continuously focused on pushing through and
beyond your boundaries, conquering a whole new challenge every day in an
atmosphere where you constantly learn and improve, this is the place for
you. We'd love to learn more about you.
</p>
<button className="btn-secondary">
Read More
</button>
</div>
</Wrapper>

{/* Action Card */}
<Wrapper>
<div className="my-90p">
<ActionCard
title={_data.ActionCard.heading}
text={_data.ActionCard.paragraph}
btn1={_data.ActionCard.primaryBtn}
btn2={_data.ActionCard.secondaryBtn}
link1={'/contact'}
link2={'/about'}
/>
</div>
</Wrapper>
</div>
</PageLayout>
);
}

+ 384
- 0
frontend/src/pages/EventsTimeline.jsx Просмотреть файл

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

import ImgStep1 from '../assets/images/CaseStudy/CentralizedSmall.png';
import ImgEvents from '../assets/images/Careers/events.png';

import Care from './../assets/icons/values/care.svg';
import Doing from './../assets/icons/values/doing.svg';
import Culture from './../assets/icons/values/culture.svg';
import Ideas from './../assets/icons/values/ideas.svg';

import CardsGrid from '../components/CardsGrid';

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

// eslint-disable-next-line no-underscore-dangle
const _data = {
heading: {
heading: 'Join Our Team of Diligent Minds',
subheading: 'Careers',
},
job: {
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: {
heading: 'A Culture That’s Serious About Work and Fun',
subheading: 'Diligent life',
italic: {
heading: 'Life At diligent',
paragraph:
'From the start, you can expect to be challenged and supported. We provide a encouraged atmosphere with knowledgeable mentors to help you advance in your career. To create an inspiring work life, we collaborate as a team both inside and outside of the office.',
heading2: 'What It Means to Work With Us',
},
cards: [
{
id: 1,
title: 'Shape the Future',
paragraph:
'We collaborate with business leaders and entrepreneurs to disrupt and push their industries forward. From startup ideas to enterprise-level product & software development, we work together as a team to transform our clients’ ideas into reality.',
},
{
id: 2,
title: 'Life-Long Learning',
paragraph:
'We believe that learning is a journey that never ends. With us, you will have the opportunity to continuously learn in an environment surrounded by other highly skilled professionals with decades of experience. Also, there are several chances for you to develop through the use of various technologies, involvement in the product definition process, conference attendance, and more.',
},
{
id: 3,
title: 'A Unique Culture',
paragraph:
'Everyone talks about a work-life balance, we do it - for two reasons. Firstly, we believe in an environment of happy people. Secondly, even if you’re highly productive, the only way to maintain productivity long-term is by taking time for the things that make you happy.',
},
{
id: 4,
title: 'Make the Impossible Better',
paragraph:
"If you have a mindset that is continuously focused on pushing through and beyond your boundaries, conquering a whole new challenge every day in an atmosphere where you constantly learn and improve, this is the place for you. We'd love to learn more about you.",
},
],
},
values: {
heading: 'Values',
cards: [
{
id: 0,
iconUrl: Care,
title: 'Care',
paragraph:
'We believe that by working together and being kind to one another, we can make a difference. We care about work colleagues, ourselves, partnerships, but also the planet. We constantly strive to be helpful, kind, and inclusive in everything we do and looking for ways to be more sustainable. ',
},
{
id: 1,
iconUrl: Culture,
title: 'Culture',
paragraph:
'Our people love what they do. We provide a fun and supportive environment that empowers our staff to grow, learn, and thrive. We are consistent and transparent in our actions and committed to our clients and colleagues. We believe that together we can achieve more.',
},
{
id: 2,
iconUrl: Doing,
title: 'Learn by Doing',
paragraph:
'Our legacy is our impact on the people around us. By being kind and helping others, we can make a positive difference and leave a lasting impression. We grow as individuals, as well as we grow as a team.',
},
{
id: 3,
iconUrl: Ideas,
title: 'Ideas Over Hierarchy',
paragraph:
'We believe that the best ideas can come from anywhere, both inside and outside our company. Our job is to seek out those ideas, shape and improve them through candid debate, and take them from concept to action.',
},
],
},
cards: [
{
id: 0,
title: 'BI Healthcare Solution System',
imgUrl:
'https://lh6.googleusercontent.com/D7N87i3udAln4YBp5SbaSI-9r2pVnnT5K2VT6p0G3dQanVgTMC2tdgz71PWOYco-7yQ=w2400',
alt: 'BI Healthcare Solution System',
link: '/casestudybi',
},
{
id: 1,
title: 'Resource Planning System',
imgUrl:
'https://lh5.googleusercontent.com/HLOh5coHfcEgDuftj1pOA9f1865xiIom5vyxTWNMKqMiivxL8Lg4c9ACzbfYYUdeuqQ=w2400',
alt: 'Resource Planning System',
link: '/casestudyresource',
},
{
id: 2,
title: 'Ticketing System for Passengers',
imgUrl:
'https://lh5.googleusercontent.com/f_G0H0C_qLHhsU8PBj6uTkNigzKiXzd24B_pgJ6UqVmBKlU2Lyxv2r5lf6uvY9d_0PY=w2400',
alt: 'Ticketing System for Passengers',
link: '/casestudyticketing',
},
],
connect: {
heading: 'Connect and Grow With Us',
paragraph:
'At Diligent, we are passionately proud of our culture and feel that everyone, including those who are not yet on the team, should have the opportunity to experience it. Because of this, we participate in Open Doors. Our coworkers are actively involved in the local tech communities. We take satisfaction in giving back as well, assisting college students or seasoned professionals who want to start a career in IT.',
subtitle: 'Check out how we have fun together!',
sliderImages: [],
},
ActionCard: {
heading: 'Step up Your Career!',
paragraph:
'We are continuously on the lookout for talented people to grow our business.',
primaryBtn: 'Apply',
secondaryBtn: 'About Us',
},
};

export default function Careers({ forwardedRef }) {
const [clickedPosition, setClickedPosition] = useState('');
const [cntCareers, setCntCareers] = useState('');
const [isLoaded, setIsLoaded] = useState('');

const api_url = process.env.REACT_APP_API_URL;

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

//useAnalytics();

useEffect(async () => {
var vid = document.getElementById('animation');
vid.playbackRate = 2;
axios
.get(
`${api_url}/api/careerspage?populate[0]=heading&populate[1]=info&populate[2]=job.icon`,
)
.then(res => {
//console.log(res.data.data.attributes);
setCntCareers(res.data.data.attributes);
setIsLoaded(true);
})
.catch(err => {
console.log(err);
setIsLoaded(false);
});
}, []);

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 (
<PageLayout>
<div className="bg-white dark:bg-dg-primary-1700 w-full pt-90p overflow-hidden">
{/* Selection Process */}
<Wrapper bg padding={' py-90p'}>
<PageTitle
left
heading="Becoming a Part of Our Team"
subheading="Selection Process"
/>
<div className="no-scroll flex flex-col items-center justify-start overflow-auto h-[75vh] pt-72p pl-3">
{/* Dynamic Image */}
<img
id="steps-image"
src={ImgStep1}
alt="Image not found"
className="absolute top-1/4 left-1/2 w-2/5 bg-fixed"
/>

{/* Section 1 */}
<div
id="steps-container"
className="relative flex flex-row items-start justify-center gap-16 min-h-[54vh] max-h[100vh]"
>
{/* Line */}
<hr className="bg-gray-400 w-full absolute -left-1/2 rotate-90" />
{/* Dot */}
<div className="z-10 p-[0.36rem] rounded-full bg-white border-solid border border-dg-primary-900 absolute -left-[0.63%] top-[1%]"></div>
<div className="w-1/2 min-w-fit ml-8">
<TimelineCard
key="1"
id="1"
title="Heading"
subtitle="Subheading"
paragraph="Paragraph over here. Lorem ipsum. Paragraph over here. Lorem ipsum."
/>
</div>
<div className="w-1/2"></div>
</div>

{/* Section 2 */}
<div className="relative flex flex-row items-start justify-center gap-16 min-h-[54vh] max-h[100vh]">
{/* Line */}
<hr className="bg-gray-400 w-full absolute -left-1/2 rotate-90" />
{/* Dot */}
<div className="z-10 p-[0.36rem] rounded-full bg-white border-solid border border-dg-primary-900 absolute -left-[0.63%] top-[1%]"></div>
<div className="w-1/2 ml-8">
<h3 className="h3-heading">{_data.selectionProcess.stepTwo.heading}</h3>
<p className="text-sm text-dark-gray dark:text-white mt-4">
{_data.selectionProcess.stepTwo.paragraph}
</p>
</div>
<div className="w-1/2"></div>
</div>

{/* Section 3 */}
<div className="relative flex flex-row items-start justify-center gap-16 min-h-[54vh] max-h[100vh]">
{/* Line */}
<hr className="bg-gray-400 w-full absolute -left-1/2 rotate-90" />
{/* Dot */}
<div className="z-10 p-[0.36rem] rounded-full bg-white border-solid border border-dg-primary-900 absolute -left-[0.63%] top-[1%]"></div>
<div className="w-1/2 ml-8">
<h3 className="h3-heading">{_data.selectionProcess.stepThree.heading}</h3>
<p className="text-sm text-dark-gray dark:text-white mt-4">
{_data.selectionProcess.stepThree.paragraph}
</p>
</div>
<div className="w-1/2"></div>
</div>

{/* Section 4 */}
<div className="relative flex flex-row items-start justify-center gap-16 min-h-[54vh] max-h[100vh]">
{/* Line */}
<hr className="bg-gray-400 w-full absolute -left-1/2 rotate-90" />
{/* Dot */}
<div className="z-10 p-[0.36rem] rounded-full bg-white border-solid border border-dg-primary-900 absolute -left-[0.63%] top-[1%]"></div>
<div className="w-1/2 ml-8">
<h3 className="h3-heading">{_data.selectionProcess.stepFour.heading}</h3>
<p className="text-sm text-dark-gray dark:text-white mt-4">
{_data.selectionProcess.stepFour.paragraph}
</p>
</div>
<div className="w-1/2"></div>
</div>

{/* Section 5 */}
<div className="relative flex flex-row items-start justify-center gap-16 min-h-[54vh] max-h[100vh]">
{/* Line */}
<hr className="bg-gray-400 w-full absolute -left-1/2 rotate-90" />
{/* Dot */}
<div className="z-10 p-[0.36rem] rounded-full bg-white border-solid border border-dg-primary-900 absolute -left-[0.63%] top-[1%]"></div>
<div className="w-1/2 ml-8">
<h3 className="h3-heading">{_data.selectionProcess.stepFive.heading}</h3>
<p className="text-sm text-dark-gray dark:text-white mt-4">
{_data.selectionProcess.stepFive.paragraph}
</p>
</div>
<div className="w-1/2"></div>
</div>
</div>
</Wrapper>

{/* Action Card */}
<Wrapper>
<div className="my-90p">
<ActionCard
title={_data.ActionCard.heading}
text={_data.ActionCard.paragraph}
btn1={_data.ActionCard.primaryBtn}
btn2={_data.ActionCard.secondaryBtn}
link1={'/contact'}
link2={'/about'}
/>
</div>
</Wrapper>
</div>
</PageLayout>
);
}

+ 90
- 74
frontend/src/pages/Home.jsx Просмотреть файл

import PortfolioSection from '../components/PortfolioSection'; import PortfolioSection from '../components/PortfolioSection';
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 useAnalytics from '../hooks/useAnalytics'; import useAnalytics from '../hooks/useAnalytics';
import ReactHelmet from '../components/shared/ReactHelmet'; import ReactHelmet from '../components/shared/ReactHelmet';
import { UIContext } from './../context/index';
import { strapiApiBuilder } from './../utils/strapiApiBuilder';


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 = [
'Heading',
'Heading.subtitle',
'Heading.title',
'WhyUsHeading',
'Cards',
'Cards.Card1',
'Cards.Card1.Image',
'Cards.Card2',
'Cards.Card2.Image',
'Cards.Card3',
'Cards.Card3.Image',
'HeroNumbers',
'HeroNumbers.number',
'ProcessHeading',
'ProcessImage',
'TechStackHeading',
'ProcessMobileImg',
'ProcessMobileImg.Image',
'CaseStudies',
'Map',
'SEO',
'SEO.metaSocial',
'SEO.metaImage',
'SEO.metaSocial.image',
'BusinessInquiry',
'BusinessInquiry.image',
'ApplyPosition',
'ApplyPosition.image',
];


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


const [contactRef, setRef] = useState(forwardedRef);
const [contactElement, setContactElement] = useState(0);
const strapi = strapiApiBuilder('w-home-page', strapiPopulate);


useAnalytics('Home page');
const [{ data, isLoading, isError }, doFetch] = useDataApi(strapi);


// const UIContext = useContext(UIContext);


// const initUIValues = UIContext ?? {
// tab: '',
// contactRef: contactRef
// };
useAnalytics('Home page');


//set Tab Title
useEffect(() => { useEffect(() => {
document.title = 'Diligent Software'; document.title = 'Diligent Software';
}, []); }, []);


useEffect(() => {
var vid = document.getElementById('animation');
vid.playbackRate = 2;
axios
.get(
`${api_url}/api/homepage?populate[0]=landing&populate[1]=why&populate[2]=why.heading&populate[3]=why.card_left.icon&populate[4]=why.card_mid.icon&populate[5]=why.card_right.icon&populate[6]=why.card_left.icon&populate[7]=why.card_mid.icon&populate[8]=why.card_right.icon&populate[9]=landing.heading`,
// api/homepage?&populate[0]=why&populate[1]=why.heading&populate[2]=why.card_left.icon&populate[3]=why.card_mid.icon&populate[4]=why.card_right.icon&populate[5]=why.card_left.icon&populate[6]=why.card_mid.icon&populate[7]=why.card_right.icon
)
.then(res => {
setCnt(res.data.data.attributes);
//console.log(res)
setIsLoaded(true);
})
.catch(err => {
console.log(err);
setIsLoaded(false);
});
}, []);


if (!isLoaded) {
if (isLoading) {
return ( 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"> <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> <video id="animation" width="540" height="540" autoPlay muted loop>
} else { } else {
return ( return (
<PageLayout> <PageLayout>
{cnt.SEO && <ReactHelmet seo={cnt.SEO} />}
{(data && data.SEO) ? <ReactHelmet seo={data.SEO} /> : null}
<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 /> */}

{/* <Tab.Group>
<Tab.List>
<Tab>Tab 1</Tab>
<Tab>Tab 2</Tab>
</Tab.List>
<Tab.Panels>
<Tab.Panel><ClientForm /></Tab.Panel>
<Tab.Panel><JobForm /></Tab.Panel>
</Tab.Panels>
</Tab.Group> */}


{/* Landing Section */} {/* Landing Section */}
<Landing data={cnt.landing.heading} />
{data ? (
<Landing
heading={data.Heading}
numbers={data.HeroNumbers.number}
paragraph={data.paragraph}
button={data.button}
/>
) : null}


{/* Why Us Section */} {/* Why Us Section */}
<WhySection data={cnt.why} />
{data ? (
<WhySection
heading={data.WhyUsHeading}
p1={data.WhyUsParagraph1}
p2={data.WhyUsParagraph2}
cards={data.Cards}
/>
) : null}


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


{/* Our Process Section */} {/* Our Process Section */}
<ProcessSection />

{data ? (
<ProcessSection
heading={data.ProcessHeading}
btn={data.ProcessCTA}
image={data.ProcessImage}
mobileImages={data.ProcessMobileImg.Image}
/>
) : null}


{/* Our Process Section */} {/* Our Process Section */}
<TechStack />
{data ? (
<TechStack heading={data.TechStackHeading} btn={data.TechStackCTA} />
) : null}


{/* Testimonials Section*/} {/* Testimonials Section*/}
<Testimonials />
{data ? <Testimonials /> : null}


{/* Social Networks Section */}
{/* <section
id="socials"
className="h-fit bg-white dark:bg-dg-primary-1700 flex flex-col items-center px-4"
>
<SocialNetworks />
</section> */}
{/* Portfolio Section*/}

{data ? (
<PortfolioSection
heading={data.CaseStudies}
cta={data.CtaForCaseStudiesCards}
/>
) : null}


<PortfolioSection />


{/* Contact Section */}
<section id="contact" className="" ref={forwardedRef}>
<Contact defaultIndex={0} />
</section>


<MapDilig />

{/* Contact Section */}
{data ? (
<section id="contact" className="" ref={forwardedRef}>
<Contact
defaultIndex={true}
position={''}
job={data.ApplyPosition}
business={data.BusinessInquiry}
/>
</section>
) : null}

{data ? <MapDilig heading={data.Map} /> : null}
</div> </div>
</PageLayout> </PageLayout>
); );

+ 88
- 160
frontend/src/pages/ProcessPage.jsx Просмотреть файл

import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import Loader from '../components/shared/Loader';
import PageTitle from '../components/shared/PageTitle'; import PageTitle from '../components/shared/PageTitle';
import useFetch from '../hooks/useFetch';
import Wrapper from '../layout/Wrapper'; import Wrapper from '../layout/Wrapper';
import ProcessCardsWrapper from '../components/shared/ProcessCardWrapper'; import ProcessCardsWrapper from '../components/shared/ProcessCardWrapper';
import ProcessCard from '../components/shared/ProcessCard'; import ProcessCard from '../components/shared/ProcessCard';
import ActionCard from '../components/shared/ActionCard'; import ActionCard from '../components/shared/ActionCard';
import axios from 'axios';


import Animation_Diligent from '../assets/animation_diligent.webm'; import Animation_Diligent from '../assets/animation_diligent.webm';


import { ReactComponent as ProcessSvg } from './../assets/images/Process.svg';
import { m } from 'framer-motion';
import PageLayout from '../layout/PageLayout'; import PageLayout from '../layout/PageLayout';
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';
import useDataApi from './../hooks/useDataApi';
import { strapiApiBuilder } from '../utils/strapiApiBuilder';
import ReactHelmet from './../components/shared/ReactHelmet';


const _data = {
heading: {
heading: 'How We Do It?',
subheading: 'Our Process',
paragraph:
'We work with our clients to deliver the full software release lifecycle, from development to final rollout. We understand how important a good process is for success because our team members have deep backgrounds in product development. Our clients can rely on us for a complete software release solution that meets their needs and achieves their desired outcomes.',
},
processImg: {
url: '',
},
cards: [
{
id: '1',
title: 'Figure It Out',
subtitle: "After understanding the company's goals, we build a digital strategy.",
paragraphs: [
{
paragraph:
'We collaborate with you to comprehend each business possibility associated with your project. Early technological issues are identified, followed by study and solution architecture. Our user-centric methodology yields results that are straightforward and interesting. To better understand your user base, we create Personas, Journey Mapping, and Usability Testing.',
},
],
},
{
id: '2',
title: 'Solution Design',
subtitle: 'Align user and business strategies.',
paragraphs: [
{
paragraph:
'User experience (UX) User research inevitably leads to design. Know your users, their requirements, and their objectives. Our multidisciplinary design team creates system flows, journey maps, annotated wireframes, final UI designs, and click-model prototypes.',
},
{
paragraph:
"Close communication is essential for success here, and concepts are iterated on both our and your teams. We'll keep optimizing until we have the ideal design that meets your needs and those of your users.",
},
],
},
{
id: '3',
title: 'Build',
subtitle: 'Delightful user experiences meet precise engineering.',
paragraphs: [
{
paragraph:
'Diligent can point you in the direction of the appropriate framework, language, and platform for your project, whether you already have a codebase or you start from scratch. Our talented group of developers includes computer scientists who are proficient in a variety of programming languages.',
},
{
paragraph:
"We'll assist you in selecting the best technology for your project. We proceed with secure front-end, back-end, and full-stack development after deciding on the optimal strategy.",
},
],
},
{
id: '4',
title: 'QA Test',
subtitle: 'Maximum efficiency, zero bugs.',
paragraphs: [
{
paragraph:
'We take pride in creating quality software. Our code is scalable, reusable, readable, and high performing. We have developed extensive testing processes and standardized Diligent Software Practices thanks to our more than 7 years of expertise in software development with a wide range of projects.',
},
],
},
{
id: '5',
title: 'Launch',
subtitle: 'Go Live!',
paragraphs: [
{
paragraph:
'We are prepared to launch after all sprints have ended and User Acceptance Testing (UAT) has been successful. Hosting is often done with Amazon AWS, which allows us to quickly grow, backup, and manage your application.',
},
{
paragraph:
'Depending on the nature and complexity of the project, one or several releases may be appropriate. Your time to market will be accelerated in either case by our agile development.',
},
],
},
{
id: '6',
title: 'Maintain and Improve',
subtitle: 'Continually optimize and grow.',
paragraphs: [
{
paragraph:
"We aim to provide long-term support for your program and establish ourselves as a reliable technological partner. We're here to support you while you update, monitor, and manage your app.",
},
{
paragraph:
'We will work with you to ensure stability and longevity. We also assist with new concepts and features. Allow us to assist you with your plan so you may keep wowing your users, clients, and investors.',
},
],
},
],
ActionCard: {
heading: 'Let’s Work Together!',
paragraph:
'Grow faster with a dedicated team of .NET & JS experts.',
primaryBtn: 'Contact Us',
secondaryBtn: 'Portfolio',
},
};
const api_url = process.env.REACT_APP_API_URL;

const strapiPopulate = [
'WorkTogether',
'Heading',
'ProcessImage',
'ProcessMobileImages',
'Step',
'Step.paragraphs',
'SEO',
'SEO.metaSocial',
'SEO.metaImage',
'SEO.metaSocial.image',
];


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


const strapi = strapiApiBuilder('processpage', strapiPopulate);

const [{ data, isLoading, isError }, doFetch] = useDataApi(strapi);

const windowInfo = useWindowSize(); const windowInfo = useWindowSize();


useEffect(() => { useEffect(() => {
else setIsMobile(false); else setIsMobile(false);
}, [windowInfo]); }, [windowInfo]);


return (
<PageLayout>
<div className="pt-32">
{_data.heading.heading && (
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>
{data && data.SEO ? <ReactHelmet seo={data.SEO} /> : null}
<div className="pt-32">
<Wrapper> <Wrapper>
<h1 className="hidden">Our Process - How We Do It?</h1>
<PageTitle
left
color
heading={_data.heading.heading}
subheading={_data.heading.subheading}
/>
{/* <div className="flex justify-center items-center mt-90p overflow-x-auto">
<div className='w-full' draggable >
<ProcessSvg className='' />
</div>
</div> */}
{data ? (
<PageTitle
left
color
heading={data.Heading.title}
subheading={data.Heading.subtitle}
/>
) : null}

<div className="relative mx-auto my-32p md:my-90p"> <div className="relative mx-auto my-32p md:my-90p">
{!isMobile ? ( {!isMobile ? (
<div className="flex w-full">
<ProcessSvg className="" />
<div className="w-full">
{data ? (
<img
src={api_url + data.ProcessImage.data.attributes.url}
alt={data.ProcessImage.data.attributes.alternativeText}
></img>
) : null}
</div> </div>
) : ( ) : (
<div className=""> <div className="">
<ProcessSlider />
<ProcessSlider images={data.ProcessMobileImages.data} />
</div> </div>
)} )}
</div> </div>
<p className="my-90p">{_data.heading.paragraph}</p>
{data ? <p className="my-90p">{data.paragraph}</p> : null}
</Wrapper>
<Wrapper bg padding={' py-90p'}>
{data
? data.Step.length > 0 && (
<ProcessCardsWrapper>
{data.Step.map((item, index) => (
<ProcessCard
key={index}
id={index + 1}
title={item.title}
subtitle={item.subtitle}
text={item.paragraphs}
numeric
/>
))}
</ProcessCardsWrapper>
)
: null}
</Wrapper> </Wrapper>
)}
<Wrapper bg padding={' py-90p'}>
{_data.cards.length > 0 && (
<ProcessCardsWrapper>
{_data.cards.map((item, index) => (
<ProcessCard
key={index}
id={item.id}
title={item.title}
subtitle={item.subtitle}
text={item.paragraphs}
numeric
<Wrapper>
<div className="my-90p">
{data ? (
<ActionCard
title={data.WorkTogether.title}
text={data.WorkTogether.paragraph}
btn1={data.WorkTogether.ButtonPrimary}
btn2={data.WorkTogether.ButtonSecondary}
link1={'/contact'}
link2={'/portfolio'}
/> />
))}
</ProcessCardsWrapper>
)}
</Wrapper>
<Wrapper>
<div className="my-90p">
<ActionCard
title={_data.ActionCard.heading}
text={_data.ActionCard.paragraph}
btn1={_data.ActionCard.primaryBtn}
btn2={_data.ActionCard.secondaryBtn}
link1={'/contact'}
link2={'/portfolio'}
/>
</div>
</Wrapper>
</div>
</PageLayout>
);
) : null}
</div>
</Wrapper>
</div>
</PageLayout>
);
}
}; };


export default ProcessPage; export default ProcessPage;

+ 79
- 50
frontend/src/pages/WorkWithUs.jsx Просмотреть файл

import React, { Children, Fragment, useEffect } from 'react'; import React, { Children, Fragment, useEffect } from 'react';
import fileDownload from 'js-file-download';
import CustomLink from '../components/root/CustomLink'; import CustomLink from '../components/root/CustomLink';
import ActionCard from '../components/shared/ActionCard'; import ActionCard from '../components/shared/ActionCard';




import '../App.css'; import '../App.css';
import useAnalytics from './../hooks/useAnalytics'; import useAnalytics from './../hooks/useAnalytics';
import { strapiApiBuilder } from './../utils/strapiApiBuilder';
import ReactHelmet from './../components/shared/ReactHelmet';
import WorkClientForm from './../components/WorkClientForm';

import MailchimpSubscribe from 'react-mailchimp-subscribe';
import { useState } from 'react';


const api_url = process.env.REACT_APP_API_URL; const api_url = process.env.REACT_APP_API_URL;
const mailchimp_url =
'https://dilig.us18.list-manage.com/subscribe/post?u=4bd507e0bc2f58fc19f284648&amp;id=09da427d96&amp;f_id=00b927e7f0';


const download = { const download = {
downloadFilePath: `${process.env.PUBLIC_URL}/DiligentCompanyOverview.pdf`, downloadFilePath: `${process.env.PUBLIC_URL}/DiligentCompanyOverview.pdf`,
'WhyWork.img', 'WhyWork.img',
'Stats', 'Stats',
'SucessParagraph', 'SucessParagraph',
'Spec',
'Specs',
'Download', 'Download',
'OfficeImg', 'OfficeImg',
'WorkTogether', 'WorkTogether',
'SEO',
'SEO.metaSocial',
'SEO.metaImage',
'SEO.metaSocial.image',
]; ];


const stringBuilder = () => {
let stringQuery = '';
strapiPopulate.map((item, index) => {
if (index !== 0) stringQuery += '&';
stringQuery += `populate=${item}`;
});
return stringQuery;
};

const NumberIcon = ({ number }) => { const NumberIcon = ({ number }) => {
return ( return (
<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"> <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">
}; };


const WorkWithUs = () => { const WorkWithUs = () => {
useAnalytics('Work With Us');
const [formSuccess, setFormSuccess] = useState(false);


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

const [{ data, isLoading, isError }, doFetch] = useDataApi(strapi);

useAnalytics('Work With Us');


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


function downloadFile(filePath) {
var link = document.createElement('a');
link.href = filePath;
link.download = filePath.substr(filePath.lastIndexOf('/') + 1);
link.click();
}

const handleFileDownload = (url, filename) => {
fetch(url).then(response => {
return response.blob().then(blob => {
//console.log(blob);
//console.log(response.body);
console.log(blob.raw);
//fileDownload(response.headers.get('Content-Type'), blob);
//fileDownload(response.url, blob);
});
});
};

useEffect(() => {
formSuccess && downloadFile(download.downloadFilePath);
}, [formSuccess]);

if (isLoading) { if (isLoading) {
return ( 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"> <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">
} else { } else {
return ( return (
<PageLayout> <PageLayout>
{data && data.SEO ? <ReactHelmet seo={data.SEO} /> : null}
<div className="mt-[48px] md:mt-[180px]"> <div className="mt-[48px] md:mt-[180px]">
<Wrapper padding={' py-[48px]'}> <Wrapper padding={' py-[48px]'}>
{data ? ( {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 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="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)]"> <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}
{data.Specs[0].text}
</div> </div>
<div className="bg-white py-32p px-[24px] rounded-[8px] text-center shadow-[0_3px_10px_rgb(0,0,0,0.2)]"> <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}
{data.Specs[1].text}
</div> </div>
<div className="bg-white py-32p px-[24px] rounded-[8px] text-center shadow-[0_3px_10px_rgb(0,0,0,0.2)]"> <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}
{data.Specs[2].text}
</div> </div>
</div> </div>
<div className="flex flex-col gap-32p sm:mt-8"> <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)]"> <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}
{data.Specs[3].text}
</div> </div>
<div className="bg-white py-32p px-[24px] rounded-[8px] text-center shadow-[0_3px_10px_rgb(0,0,0,0.2)]"> <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}
{data.Specs[4].text}
</div> </div>
<div className="bg-white py-32p px-[24px] rounded-[8px] text-center shadow-[0_3px_10px_rgb(0,0,0,0.2)]"> <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}
{data.Specs[5].text}
</div> </div>
</div> </div>
<div className="flex flex-col gap-32p sm:mb-8"> <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)]"> <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}
{data.Specs[6].text}
</div> </div>
<div className="bg-white py-32p px-[24px] rounded-[8px] text-center shadow-[0_3px_10px_rgb(0,0,0,0.2)]"> <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}
{data.Specs[7].text}
</div> </div>
<div className="bg-white py-32p px-[24px] rounded-[8px] text-center shadow-[0_3px_10px_rgb(0,0,0,0.2)]"> <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}
{data.Specs[8].text}
</div> </div>
</div> </div>
</div> </div>
></img> ></img>
</div> </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>
<CustomLink
href={download.downloadFilePath}
downloadFile={download.downloadFileName}
context={'Company Overview'}
>
<p>{data.Download.button}</p>
</CustomLink>
</div>
<MailchimpSubscribe
url={mailchimp_url}
render={({ subscribe, status, message }) => (
<>
<WorkClientForm
data={data.Download}
download={download}
status={status}
message={message}
onValidated={formData => subscribe(formData)}
/>
{status === 'success' ? setFormSuccess(true) : setFormSuccess(false)}
</>
)}
/>
</div> </div>
) : null} ) : null}
{data ? ( {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}
<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> </PageLayout>
); );

+ 27
- 1
frontend/src/routes.js Просмотреть файл

import PrivacyPolicy from "./pages/PrivacyPolicy"; import PrivacyPolicy from "./pages/PrivacyPolicy";
import ProcessPage from "./pages/ProcessPage"; import ProcessPage from "./pages/ProcessPage";
import WorkWithUs from "./pages/WorkWithUs"; import WorkWithUs from "./pages/WorkWithUs";

import EventsTimeline from "./pages/EventsTimeline";
import DiligentLife from "./pages/DiligentLife";
import DiligentMinds from "./pages/DiligentMinds";
const routes = [ const routes = [
{ {
path: '/', path: '/',
title: 'Careers', title: 'Careers',
exact: true, exact: true,
nav:true, nav:true,
drop: [
// enable after we add content
// {
// path:'/diligentlife',
// component: <DiligentLife />,
// title: 'Diligent Life',
// exact: true,
// nav:true,
// },
// {
// path:"/diligentminds",
// component: <DiligentMinds />,
// title: 'Diligent Minds',
// exact: true,
// nav:true,
// },
// {
// path:"/eventstimeline",
// component: <EventsTimeline />,
// title: 'Events Timeline',
// exact: true,
// nav:true,
// },
],
}, },
{ {
path: '/about', path: '/about',

+ 5
- 0
frontend/src/styles/cards.css Просмотреть файл

.card-plain { .card-plain {
@apply p-12 @apply p-12
} }

} }


.leaf { .leaf {
border: 1px solid #D4D4D4; border: 1px solid #D4D4D4;
border-radius: 18px; border-radius: 18px;
} }

.active-image {
opacity: 1 !important;
}

+ 1
- 1
frontend/src/styles/text.css Просмотреть файл



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


.subheading { .subheading {

+ 2
- 2
frontend/tailwind.config.js Просмотреть файл

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

+ 29
- 2
frontend/yarn.lock Просмотреть файл

"resolved" "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz" "resolved" "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz"
"version" "4.2.9" "version" "4.2.9"


"gsap@^3.11.4":
"integrity" "sha512-McHhEguHyExMMnjqKA8G+7TvxmlKQGMbjgwAilnFe1e4id7V/tFveRQ2YMZhTYu0oxHGWvbPltdVYQOu3z1SCA=="
"resolved" "https://registry.npmjs.org/gsap/-/gsap-3.11.4.tgz"
"version" "3.11.4"

"gzip-size@^6.0.0": "gzip-size@^6.0.0":
"integrity" "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==" "integrity" "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q=="
"resolved" "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz" "resolved" "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz"
"import-local" "^3.0.2" "import-local" "^3.0.2"
"jest-cli" "^27.4.7" "jest-cli" "^27.4.7"


"js-file-download@^0.4.12":
"integrity" "sha512-rML+NkoD08p5Dllpjo0ffy4jRHeY6Zsapvr/W86N7E0yuzAO6qa5X9+xog6zQNlH102J7IXljNY2FtS6Lj3ucg=="
"resolved" "https://registry.npmjs.org/js-file-download/-/js-file-download-0.4.12.tgz"
"version" "0.4.12"

"js-tokens@^3.0.0 || ^4.0.0", "js-tokens@^4.0.0": "js-tokens@^3.0.0 || ^4.0.0", "js-tokens@^4.0.0":
"integrity" "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" "integrity" "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
"resolved" "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" "resolved" "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"
dependencies: dependencies:
"js-tokens" "^3.0.0 || ^4.0.0" "js-tokens" "^3.0.0 || ^4.0.0"


"lottie-web@^5.5.7":
"integrity" "sha512-d0PFIGiwuMsJYaF4uPo+qG8dEorlI+xFI2zrrFtE1bGO4WoLIz+NjremxEq1swpR7juR10aeOtmNh3d6G3ub0A=="
"resolved" "https://registry.npmjs.org/lottie-web/-/lottie-web-5.10.2.tgz"
"version" "5.10.2"

"lower-case@^2.0.2": "lower-case@^2.0.2":
"integrity" "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==" "integrity" "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg=="
"resolved" "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz" "resolved" "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.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.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":
"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", "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"
"react-fast-compare" "^3.2.0" "react-fast-compare" "^3.2.0"
"shallowequal" "^1.1.0" "shallowequal" "^1.1.0"


"react-intersection-observer@^9.4.1":
"integrity" "sha512-IXpIsPe6BleFOEHKzKh5UjwRUaz/JYS0lT/HPsupWEQou2hDqjhLMStc5zyE3eQVT4Fk3FufM8Fw33qW1uyeiw=="
"resolved" "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.4.1.tgz"
"version" "9.4.1"

"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@^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":
"react-useanimations@^2.10.0":
"integrity" "sha512-MzGNv8vkvb6qEvMBCj+O6nUloUHSJRubMAH3uE7J4M+pjt5ud5xDaXBrQgv5GbvBg29XzviKWHTfvvkofDEu+Q=="
"resolved" "https://registry.npmjs.org/react-useanimations/-/react-useanimations-2.10.0.tgz"
"version" "2.10.0"
dependencies:
"lottie-web" "^5.5.7"

"react@*", "react@^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "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"

Загрузка…
Отмена
Сохранить