From a2b296cc0d156bfe73322b364e9a8f47f0c457b9 Mon Sep 17 00:00:00 2001 From: Rediet-Ferew Date: Mon, 22 May 2023 11:21:08 +0300 Subject: [PATCH 1/6] implement fetch from json-server for home page --- .../components/home/Activities.tsx | 2 +- .../components/home/SuccessRate.tsx | 2 +- Web/starter_project_vanguard/data/db.json | 4 ++ .../data/home/activities.json | 58 +++++++++++++++++++ Web/starter_project_vanguard/store/index.ts | 8 +++ 5 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 Web/starter_project_vanguard/data/home/activities.json diff --git a/Web/starter_project_vanguard/components/home/Activities.tsx b/Web/starter_project_vanguard/components/home/Activities.tsx index 2cc9685ec..63f5dd1f5 100644 --- a/Web/starter_project_vanguard/components/home/Activities.tsx +++ b/Web/starter_project_vanguard/components/home/Activities.tsx @@ -44,4 +44,4 @@ const Activities: React.FC = ({ ) } -export default Activities +export default Activities \ No newline at end of file diff --git a/Web/starter_project_vanguard/components/home/SuccessRate.tsx b/Web/starter_project_vanguard/components/home/SuccessRate.tsx index e6ebffabb..325b6cd1f 100644 --- a/Web/starter_project_vanguard/components/home/SuccessRate.tsx +++ b/Web/starter_project_vanguard/components/home/SuccessRate.tsx @@ -43,4 +43,4 @@ const SuccessRate: React.FC = () => { ) } -export default SuccessRate +export default SuccessRate \ No newline at end of file diff --git a/Web/starter_project_vanguard/data/db.json b/Web/starter_project_vanguard/data/db.json index 6c0720345..f6ba05c43 100644 --- a/Web/starter_project_vanguard/data/db.json +++ b/Web/starter_project_vanguard/data/db.json @@ -165,6 +165,7 @@ } ] } +<<<<<<< HEAD ], "team-members": [ @@ -291,4 +292,7 @@ } ] +======= +] +>>>>>>> cb48f84 (implement fetch from json-server for home page) } diff --git a/Web/starter_project_vanguard/data/home/activities.json b/Web/starter_project_vanguard/data/home/activities.json new file mode 100644 index 000000000..966bb834d --- /dev/null +++ b/Web/starter_project_vanguard/data/home/activities.json @@ -0,0 +1,58 @@ +{ + "activities": + [ + { + "id" : 1, + "url": "/img/home/activity-1.jpg", + "title": "Internships", + "description": + "Students who passed their interviews got 3-month internships to gain experience in building scalable products that are widely used around the world.", + "altText": "Picture of intern students" + + }, + { + "id" : 2, + "url": "/img/home/activity-2.jpg", + "title": "360° Training", + "description": + "A2SV upskills students with a 360° software engineering program that focuses on problem-solving, effective speaking, and personal development.", + "altText":"Picture of training students" + }, + { + "id" : 3, + "url": "/img/home/activity-3.jpg", + "title": "Social Projects", + "description": + "Students work on social projects with industry experts to address the most pressing problems in their community.", + "altText":"Picture of students participating in social activities" + + } + ], + + "success-rates" : [ + { + "id": 1, + "year": "2019", + "success": "Founded", + "average": "5% average" + }, + { + "id": 2, + "year": "2020", + "success": "27%", + "average": "5.2% average" + }, + { + "id": 3, + "year": "2021", + "success": "59%", + "average": "3.9% average" + }, + { + "id": 4, + "year": "2022", + "success": "70%", + "average": "2.6% average" + } +] + } \ No newline at end of file diff --git a/Web/starter_project_vanguard/store/index.ts b/Web/starter_project_vanguard/store/index.ts index 95d68fa63..183ca398d 100644 --- a/Web/starter_project_vanguard/store/index.ts +++ b/Web/starter_project_vanguard/store/index.ts @@ -4,11 +4,16 @@ import { configureStore } from '@reduxjs/toolkit' import { aboutApi } from './about/about-api' import { successStoryApi } from '@/store/features/success-story/success-story-api' import { getBlogs } from '@/store/features/blog/blogs-api' +<<<<<<< HEAD import { homeApi } from '@/store/features/home/home-api' import { userApi } from '@pages/api/profile' import { singleBlogApi } from '@/store/features/blog/single-blog-api' import { teamsApi } from '@/store/features/teams/teams-api' +import { homeApi } from './features/home/home-api' + + + export const store = configureStore({ reducer: { [successStoryApi.reducerPath]: successStoryApi.reducer, @@ -16,9 +21,11 @@ export const store = configureStore({ [aboutApi.reducerPath]: aboutApi.reducer, [getBlogs.reducerPath]: getBlogs.reducer, [homeApi.reducerPath]: homeApi.reducer, + [teamsApi.reducerPath]: teamsApi.reducer, [userApi.reducerPath]: userApi.reducer, [singleBlogApi.reducerPath]: singleBlogApi.reducer, + }, middleware: (getDefaultMiddleware) => { return getDefaultMiddleware() @@ -31,6 +38,7 @@ export const store = configureStore({ .concat(userApi.miidleware) .concat(singleBlogApi.middleware) + }, },) From 272f5f41131c19093f69a1c5c3835fb9537a7566 Mon Sep 17 00:00:00 2001 From: Rediet-Ferew Date: Mon, 22 May 2023 14:15:58 +0300 Subject: [PATCH 2/6] remove unwanted imports --- .../components/home/Activities.tsx | 2 +- .../components/home/SuccessRate.tsx | 2 +- .../data/home/activities.json | 58 ------------------- 3 files changed, 2 insertions(+), 60 deletions(-) delete mode 100644 Web/starter_project_vanguard/data/home/activities.json diff --git a/Web/starter_project_vanguard/components/home/Activities.tsx b/Web/starter_project_vanguard/components/home/Activities.tsx index 63f5dd1f5..2cc9685ec 100644 --- a/Web/starter_project_vanguard/components/home/Activities.tsx +++ b/Web/starter_project_vanguard/components/home/Activities.tsx @@ -44,4 +44,4 @@ const Activities: React.FC = ({ ) } -export default Activities \ No newline at end of file +export default Activities diff --git a/Web/starter_project_vanguard/components/home/SuccessRate.tsx b/Web/starter_project_vanguard/components/home/SuccessRate.tsx index 325b6cd1f..e6ebffabb 100644 --- a/Web/starter_project_vanguard/components/home/SuccessRate.tsx +++ b/Web/starter_project_vanguard/components/home/SuccessRate.tsx @@ -43,4 +43,4 @@ const SuccessRate: React.FC = () => { ) } -export default SuccessRate \ No newline at end of file +export default SuccessRate diff --git a/Web/starter_project_vanguard/data/home/activities.json b/Web/starter_project_vanguard/data/home/activities.json deleted file mode 100644 index 966bb834d..000000000 --- a/Web/starter_project_vanguard/data/home/activities.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "activities": - [ - { - "id" : 1, - "url": "/img/home/activity-1.jpg", - "title": "Internships", - "description": - "Students who passed their interviews got 3-month internships to gain experience in building scalable products that are widely used around the world.", - "altText": "Picture of intern students" - - }, - { - "id" : 2, - "url": "/img/home/activity-2.jpg", - "title": "360° Training", - "description": - "A2SV upskills students with a 360° software engineering program that focuses on problem-solving, effective speaking, and personal development.", - "altText":"Picture of training students" - }, - { - "id" : 3, - "url": "/img/home/activity-3.jpg", - "title": "Social Projects", - "description": - "Students work on social projects with industry experts to address the most pressing problems in their community.", - "altText":"Picture of students participating in social activities" - - } - ], - - "success-rates" : [ - { - "id": 1, - "year": "2019", - "success": "Founded", - "average": "5% average" - }, - { - "id": 2, - "year": "2020", - "success": "27%", - "average": "5.2% average" - }, - { - "id": 3, - "year": "2021", - "success": "59%", - "average": "3.9% average" - }, - { - "id": 4, - "year": "2022", - "success": "70%", - "average": "2.6% average" - } -] - } \ No newline at end of file From 1f6cdc4c1c24ffa0afbd6d278565acd21cb9a8fe Mon Sep 17 00:00:00 2001 From: Rediet-Ferew Date: Tue, 23 May 2023 16:42:36 +0300 Subject: [PATCH 3/6] implementing doctors and doctor profile page --- Web/web_assessment/components/DoctorCard.tsx | 34 +++ Web/web_assessment/components/DoctorList.tsx | 29 +++ Web/web_assessment/components/SearchBar.tsx | 48 ++++ Web/web_assessment/package-lock.json | 211 ++++++++++++++++++ Web/web_assessment/package.json | 2 + Web/web_assessment/pages/_app.tsx | 13 +- Web/web_assessment/pages/doctors/[id].tsx | 34 +++ Web/web_assessment/pages/doctors/index.tsx | 12 + Web/web_assessment/pages/index.tsx | 128 +---------- .../store/features/doctors/doctors-api.ts | 28 +++ Web/web_assessment/store/index.ts | 19 ++ 11 files changed, 437 insertions(+), 121 deletions(-) create mode 100644 Web/web_assessment/components/DoctorCard.tsx create mode 100644 Web/web_assessment/components/DoctorList.tsx create mode 100644 Web/web_assessment/components/SearchBar.tsx create mode 100644 Web/web_assessment/pages/doctors/[id].tsx create mode 100644 Web/web_assessment/pages/doctors/index.tsx create mode 100644 Web/web_assessment/store/features/doctors/doctors-api.ts create mode 100644 Web/web_assessment/store/index.ts diff --git a/Web/web_assessment/components/DoctorCard.tsx b/Web/web_assessment/components/DoctorCard.tsx new file mode 100644 index 000000000..6b97f3b87 --- /dev/null +++ b/Web/web_assessment/components/DoctorCard.tsx @@ -0,0 +1,34 @@ +import React from 'react' +import Image from 'next/image' +import Link from 'next/link' + +interface Props { + id:string; + photoUrl: string; + name: string; + specialty: string; + address: string; + } +const DoctorCard: React.FC = ({ id, photoUrl, name, specialty, address }) => { + + return ( + +
+
+
+ {name} +
+
+
+

{name}

+
+

{specialty}

+
+ +

{address}

+
+
+ + ) +} +export default DoctorCard diff --git a/Web/web_assessment/components/DoctorList.tsx b/Web/web_assessment/components/DoctorList.tsx new file mode 100644 index 000000000..fcf24d99c --- /dev/null +++ b/Web/web_assessment/components/DoctorList.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { useGetDoctorsQuery } from '@/store/features/doctors/doctors-api'; +import DoctorCard from './DoctorCard' +import SearchBar from './SearchBar' +const DoctorsList: React.FC = () => { + const { data: response, isLoading, isError } = useGetDoctorsQuery(''); + const doctors = response?.data; + + if (isLoading) { + return
Loading...
; + } + + if (isError) { + return
Error loading doctors
; + } + + return ( + +
+ + {Array.isArray(doctors) && doctors.map((doctor:any) => ( + + ))} +
+ ); + +}; + +export default DoctorsList; diff --git a/Web/web_assessment/components/SearchBar.tsx b/Web/web_assessment/components/SearchBar.tsx new file mode 100644 index 000000000..b33631c2b --- /dev/null +++ b/Web/web_assessment/components/SearchBar.tsx @@ -0,0 +1,48 @@ +import React, { useState } from 'react'; +import { useSearchDoctorsQuery } from '@/store/features/doctors/doctors-api'; +import DoctorCard from './DoctorCard' +interface SearchResult { + id: number; + title: string; +} + +const SearchBar: React.FC = () => { + const [searchTerm, setSearchTerm] = useState(''); + const { data: doctors, isLoading, isError } = useSearchDoctorsQuery(searchTerm); + + const handleSearch = (event: React.FormEvent) => { + event.preventDefault(); + // Call the search API with the current search term + setSearchTerm(event.currentTarget.search.value); + }; + + return ( +
+
+
+ + +
+
+ {isLoading &&
Loading...
} + {isError &&
Error fetching search results
} + {Array.isArray(doctors) && doctors.map((doctor:any) => ( + + ))} + + +
+ ); +}; + +export default SearchBar; diff --git a/Web/web_assessment/package-lock.json b/Web/web_assessment/package-lock.json index 5232940f5..c7bffad7c 100644 --- a/Web/web_assessment/package-lock.json +++ b/Web/web_assessment/package-lock.json @@ -8,6 +8,7 @@ "name": "web_assessment", "version": "0.1.0", "dependencies": { + "@reduxjs/toolkit": "^1.9.5", "@types/node": "20.2.3", "@types/react": "18.2.6", "@types/react-dom": "18.2.4", @@ -18,6 +19,7 @@ "postcss": "8.4.23", "react": "18.2.0", "react-dom": "18.2.0", + "react-redux": "^8.0.5", "tailwindcss": "3.3.2", "typescript": "5.0.4" } @@ -373,6 +375,29 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@reduxjs/toolkit": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.5.tgz", + "integrity": "sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ==", + "dependencies": { + "immer": "^9.0.21", + "redux": "^4.2.1", + "redux-thunk": "^2.4.2", + "reselect": "^4.1.8" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.0.2" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, "node_modules/@rushstack/eslint-patch": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.0.tgz", @@ -386,6 +411,15 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -424,6 +458,11 @@ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, "node_modules/@typescript-eslint/parser": { "version": "5.59.6", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.6.tgz", @@ -2148,6 +2187,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, "node_modules/human-signals": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", @@ -2164,6 +2211,15 @@ "node": ">= 4" } }, + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -3402,6 +3458,49 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/react-redux": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz", + "integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==", + "dependencies": { + "@babel/runtime": "^7.12.1", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/use-sync-external-store": "^0.0.3", + "hoist-non-react-statics": "^3.3.2", + "react-is": "^18.0.0", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "@types/react": "^16.8 || ^17.0 || ^18.0", + "@types/react-dom": "^16.8 || ^17.0 || ^18.0", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0", + "react-native": ">=0.59", + "redux": "^4" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/react-redux/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -3421,6 +3520,22 @@ "node": ">=8.10.0" } }, + "node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/redux-thunk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", + "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", + "peerDependencies": { + "redux": "^4" + } + }, "node_modules/regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", @@ -3442,6 +3557,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/reselect": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", + "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" + }, "node_modules/resolve": { "version": "1.22.2", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", @@ -4151,6 +4271,14 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -4476,6 +4604,17 @@ "tslib": "^2.5.0" } }, + "@reduxjs/toolkit": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.5.tgz", + "integrity": "sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ==", + "requires": { + "immer": "^9.0.21", + "redux": "^4.2.1", + "redux-thunk": "^2.4.2", + "reselect": "^4.1.8" + } + }, "@rushstack/eslint-patch": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.0.tgz", @@ -4489,6 +4628,15 @@ "tslib": "^2.4.0" } }, + "@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -4527,6 +4675,11 @@ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" }, + "@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, "@typescript-eslint/parser": { "version": "5.59.6", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.6.tgz", @@ -5727,6 +5880,14 @@ "has-symbols": "^1.0.2" } }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, "human-signals": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", @@ -5737,6 +5898,11 @@ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==" }, + "immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==" + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -6523,6 +6689,26 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "react-redux": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz", + "integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==", + "requires": { + "@babel/runtime": "^7.12.1", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/use-sync-external-store": "^0.0.3", + "hoist-non-react-statics": "^3.3.2", + "react-is": "^18.0.0", + "use-sync-external-store": "^1.0.0" + }, + "dependencies": { + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + } + } + }, "read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -6539,6 +6725,20 @@ "picomatch": "^2.2.1" } }, + "redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "requires": { + "@babel/runtime": "^7.9.2" + } + }, + "redux-thunk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", + "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", + "requires": {} + }, "regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", @@ -6554,6 +6754,11 @@ "functions-have-names": "^1.2.3" } }, + "reselect": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", + "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" + }, "resolve": { "version": "1.22.2", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", @@ -7022,6 +7227,12 @@ "punycode": "^2.1.0" } }, + "use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "requires": {} + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/Web/web_assessment/package.json b/Web/web_assessment/package.json index b25d01a09..22e901303 100644 --- a/Web/web_assessment/package.json +++ b/Web/web_assessment/package.json @@ -9,6 +9,7 @@ "lint": "next lint" }, "dependencies": { + "@reduxjs/toolkit": "^1.9.5", "@types/node": "20.2.3", "@types/react": "18.2.6", "@types/react-dom": "18.2.4", @@ -19,6 +20,7 @@ "postcss": "8.4.23", "react": "18.2.0", "react-dom": "18.2.0", + "react-redux": "^8.0.5", "tailwindcss": "3.3.2", "typescript": "5.0.4" } diff --git a/Web/web_assessment/pages/_app.tsx b/Web/web_assessment/pages/_app.tsx index 021681f4d..2b99dbc1b 100644 --- a/Web/web_assessment/pages/_app.tsx +++ b/Web/web_assessment/pages/_app.tsx @@ -1,6 +1,17 @@ import '@/styles/globals.css' import type { AppProps } from 'next/app' +import { store } from '../store' +import { Provider } from 'react-redux' + export default function App({ Component, pageProps }: AppProps) { - return + return ( + <> + + + {' '} + + + + ) } diff --git a/Web/web_assessment/pages/doctors/[id].tsx b/Web/web_assessment/pages/doctors/[id].tsx new file mode 100644 index 000000000..58f04f666 --- /dev/null +++ b/Web/web_assessment/pages/doctors/[id].tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { useRouter } from 'next/router'; +import { useGetDoctorProfileQuery } from '@/store/features/doctors/doctors-api'; + +const DoctorProfile: React.FC = () => { + const router = useRouter(); + const id = router.query.id as string; + const { data: doctor, isLoading, isError } = useGetDoctorProfileQuery(id); + + if (isLoading) { + return
Loading...
; + } + + if (isError) { + return
Error fetching todo
; + } + + if (!doctor) { + return
Todo not found
; + } + return ( +
+
+ {doctor.fullName} +
+
+

{doctor.fullName}

+ +
+
+ ); + +}; +export default DoctorProfile \ No newline at end of file diff --git a/Web/web_assessment/pages/doctors/index.tsx b/Web/web_assessment/pages/doctors/index.tsx new file mode 100644 index 000000000..5d1d3399b --- /dev/null +++ b/Web/web_assessment/pages/doctors/index.tsx @@ -0,0 +1,12 @@ +import DoctorCard from "@/components/DoctorCard" +import DoctorList from "@/components/DoctorList" + +export default function HoHakimHub() { + return ( +
+ + +
+ + ) +} \ No newline at end of file diff --git a/Web/web_assessment/pages/index.tsx b/Web/web_assessment/pages/index.tsx index eca9da7b1..24ca35634 100644 --- a/Web/web_assessment/pages/index.tsx +++ b/Web/web_assessment/pages/index.tsx @@ -1,124 +1,12 @@ -import Image from 'next/image' -import { Inter } from 'next/font/google' - -const inter = Inter({ subsets: ['latin'] }) +import DoctorCard from "@/components/DoctorCard" +import DoctorList from "@/components/DoctorList" export default function Home() { return ( -
-
-

- Get started by editing  - pages/index.tsx -

- -
- -
- Next.js Logo -
- - -
+
+ {/* */} + +
+ ) -} +} \ No newline at end of file diff --git a/Web/web_assessment/store/features/doctors/doctors-api.ts b/Web/web_assessment/store/features/doctors/doctors-api.ts new file mode 100644 index 000000000..560e02f06 --- /dev/null +++ b/Web/web_assessment/store/features/doctors/doctors-api.ts @@ -0,0 +1,28 @@ + +import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; + +export const doctorsApi = createApi({ + reducerPath: "doctorsApi", + baseQuery: fetchBaseQuery({ baseUrl: 'https://hakimhub-api-dev-wtupbmwpnq-uc.a.run.app/api/v1', + // Set the default request method to POST + headers: { + 'Content-Type': 'application/json', + }, +}), + endpoints: (builder) => ({ + getDoctors: builder.query({ + query: (keyword) =>({ url:"search?institutions=false&articles=False", method: 'POST',}), + }), + getDoctorProfile: builder.query({ + query: (id) =>({ + url:"users/doctorProfile/${id}", + method:'GET' + }) + }), + searchDoctors: builder.query({ + query: (keyword) =>({ url:"search?keyword=${keyword}institutions=false&articles=False", method:'POST'}), + }), + }), +}); + +export const { useGetDoctorsQuery, useGetDoctorProfileQuery, useSearchDoctorsQuery } = doctorsApi; \ No newline at end of file diff --git a/Web/web_assessment/store/index.ts b/Web/web_assessment/store/index.ts new file mode 100644 index 000000000..9638b37f9 --- /dev/null +++ b/Web/web_assessment/store/index.ts @@ -0,0 +1,19 @@ + +import { doctorsApi } from './features/doctors/doctors-api' +import { configureStore } from '@reduxjs/toolkit' + +export const store = configureStore({ + reducer: { + [doctorsApi.reducerPath]: doctorsApi.reducer, + + }, + middleware: (getDefaultMiddleware) => { + return getDefaultMiddleware() + + .concat(doctorsApi.middleware) + + }, +},) + +export type AppDispatch = typeof store.dispatch +export type RootState = ReturnType From 23d8bbdaa310b02cf9f4c89f66d603fcf5645b9d Mon Sep 17 00:00:00 2001 From: Rediet-Ferew Date: Tue, 23 May 2023 16:47:07 +0300 Subject: [PATCH 4/6] implementing doctors and doctor profile page --- Web/web_assessment/store/features/doctors/doctors-api.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Web/web_assessment/store/features/doctors/doctors-api.ts b/Web/web_assessment/store/features/doctors/doctors-api.ts index 560e02f06..bf4475366 100644 --- a/Web/web_assessment/store/features/doctors/doctors-api.ts +++ b/Web/web_assessment/store/features/doctors/doctors-api.ts @@ -14,13 +14,11 @@ export const doctorsApi = createApi({ query: (keyword) =>({ url:"search?institutions=false&articles=False", method: 'POST',}), }), getDoctorProfile: builder.query({ - query: (id) =>({ - url:"users/doctorProfile/${id}", - method:'GET' - }) + query: (id) => `users/doctorProfile/${id}`, + }), searchDoctors: builder.query({ - query: (keyword) =>({ url:"search?keyword=${keyword}institutions=false&articles=False", method:'POST'}), + query: (keyword) =>({ url:`search?keyword=${keyword}institutions=false&articles=False`, method:'POST'}), }), }), }); From d0c35f4ba8290ef541320937af44d3d47b16b548 Mon Sep 17 00:00:00 2001 From: Rediet-Ferew Date: Wed, 24 May 2023 11:58:39 +0300 Subject: [PATCH 5/6] implement search component --- Web/web_assessment/components/DoctorCard.tsx | 2 +- Web/web_assessment/components/DoctorList.tsx | 85 +++++++++++++------ Web/web_assessment/components/SearchBar.tsx | 48 ----------- Web/web_assessment/pages/doctors/[id].tsx | 42 ++++++--- Web/web_assessment/pages/doctors/index.tsx | 15 ++-- .../store/features/doctors/doctors-api.ts | 27 +++--- 6 files changed, 112 insertions(+), 107 deletions(-) delete mode 100644 Web/web_assessment/components/SearchBar.tsx diff --git a/Web/web_assessment/components/DoctorCard.tsx b/Web/web_assessment/components/DoctorCard.tsx index 6b97f3b87..e7643b3b4 100644 --- a/Web/web_assessment/components/DoctorCard.tsx +++ b/Web/web_assessment/components/DoctorCard.tsx @@ -21,7 +21,7 @@ const DoctorCard: React.FC = ({ id, photoUrl, name, specialty, address })

{name}

-
+

{specialty}

diff --git a/Web/web_assessment/components/DoctorList.tsx b/Web/web_assessment/components/DoctorList.tsx index fcf24d99c..b88df3a69 100644 --- a/Web/web_assessment/components/DoctorList.tsx +++ b/Web/web_assessment/components/DoctorList.tsx @@ -1,29 +1,64 @@ -import React from 'react'; -import { useGetDoctorsQuery } from '@/store/features/doctors/doctors-api'; -import DoctorCard from './DoctorCard' -import SearchBar from './SearchBar' -const DoctorsList: React.FC = () => { - const { data: response, isLoading, isError } = useGetDoctorsQuery(''); +import React from "react"; +import { useState, useEffect } from "react"; +import { useSearchDoctorsQuery } from "@/store/features/doctors/doctors-api"; +import DoctorCard from "./DoctorCard"; + + +const DoctorList: React.FC = () => { + const [searchTerm, setSearchTerm] = useState(""); + + const { + data: response, + isLoading, + isError, + } = useSearchDoctorsQuery(searchTerm); const doctors = response?.data; - - if (isLoading) { - return
Loading...
; - } - if (isError) { - return
Error loading doctors
; - } - - return ( - -
- - {Array.isArray(doctors) && doctors.map((doctor:any) => ( - - ))} -
- ); - + const handleSearch = (event: React.FormEvent) => { + event.preventDefault(); + // Call the search API with the current search term + setSearchTerm(event.currentTarget.search.value); + }; + + const handleInputChange = (event: React.ChangeEvent) => { + setSearchTerm(event.target.value); + }; + + return ( +
+
+
+ + +
+
+ {isLoading &&
Loading...
} + {isError &&
Error fetching search results
} + {Array.isArray(doctors) && + doctors.map((doctor: any) => ( + + ))} +
+ ); }; -export default DoctorsList; +export default DoctorList; diff --git a/Web/web_assessment/components/SearchBar.tsx b/Web/web_assessment/components/SearchBar.tsx deleted file mode 100644 index b33631c2b..000000000 --- a/Web/web_assessment/components/SearchBar.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import React, { useState } from 'react'; -import { useSearchDoctorsQuery } from '@/store/features/doctors/doctors-api'; -import DoctorCard from './DoctorCard' -interface SearchResult { - id: number; - title: string; -} - -const SearchBar: React.FC = () => { - const [searchTerm, setSearchTerm] = useState(''); - const { data: doctors, isLoading, isError } = useSearchDoctorsQuery(searchTerm); - - const handleSearch = (event: React.FormEvent) => { - event.preventDefault(); - // Call the search API with the current search term - setSearchTerm(event.currentTarget.search.value); - }; - - return ( -
-
-
- - -
-
- {isLoading &&
Loading...
} - {isError &&
Error fetching search results
} - {Array.isArray(doctors) && doctors.map((doctor:any) => ( - - ))} - - -
- ); -}; - -export default SearchBar; diff --git a/Web/web_assessment/pages/doctors/[id].tsx b/Web/web_assessment/pages/doctors/[id].tsx index 58f04f666..8438306ee 100644 --- a/Web/web_assessment/pages/doctors/[id].tsx +++ b/Web/web_assessment/pages/doctors/[id].tsx @@ -4,8 +4,8 @@ import { useGetDoctorProfileQuery } from '@/store/features/doctors/doctors-api'; const DoctorProfile: React.FC = () => { const router = useRouter(); - const id = router.query.id as string; - const { data: doctor, isLoading, isError } = useGetDoctorProfileQuery(id); + const id = router.query.id; + const { data: doctor, isLoading, isError } = useGetDoctorProfileQuery(id as string); if (isLoading) { return
Loading...
; @@ -19,16 +19,38 @@ const DoctorProfile: React.FC = () => { return
Todo not found
; } return ( -
-
- {doctor.fullName} -
-
-

{doctor.fullName}

- +
+
+
+ Doctor Profile +
+
+

Dr. John Doe

+

Specialist in Cardiology

+
+
+

About

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod, diam vel tincidunt bibendum, velit sapien luctus velit, vel lacinia velit velit vel velit. Sed euismod, diam vel tincidunt bibendum, velit sapien luctus velit, vel lacinia velit velit vel velit.

+
+
+

Education

+
    +
  • Doctor of Medicine, University of California, Los Angeles
  • +
  • Bachelor of Science in Biology, University of California, Berkeley
  • +
+
+
+

Contact Info

+
    +
  • Email: john.doe@hospital.com
  • +
  • Phone: (123) 456-7890
  • +
  • Address: 123 Main St, Los Angeles, CA 90001
  • +
+
); - }; + + export default DoctorProfile \ No newline at end of file diff --git a/Web/web_assessment/pages/doctors/index.tsx b/Web/web_assessment/pages/doctors/index.tsx index 5d1d3399b..5abb43e38 100644 --- a/Web/web_assessment/pages/doctors/index.tsx +++ b/Web/web_assessment/pages/doctors/index.tsx @@ -1,12 +1,9 @@ -import DoctorCard from "@/components/DoctorCard" -import DoctorList from "@/components/DoctorList" +import DoctorList from "@/components/DoctorList"; export default function HoHakimHub() { return ( -
- - -
- - ) -} \ No newline at end of file +
+ +
+ ); +} diff --git a/Web/web_assessment/store/features/doctors/doctors-api.ts b/Web/web_assessment/store/features/doctors/doctors-api.ts index bf4475366..319536797 100644 --- a/Web/web_assessment/store/features/doctors/doctors-api.ts +++ b/Web/web_assessment/store/features/doctors/doctors-api.ts @@ -1,26 +1,25 @@ - -import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; +import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; export const doctorsApi = createApi({ reducerPath: "doctorsApi", - baseQuery: fetchBaseQuery({ baseUrl: 'https://hakimhub-api-dev-wtupbmwpnq-uc.a.run.app/api/v1', - // Set the default request method to POST - headers: { - 'Content-Type': 'application/json', - }, -}), + baseQuery: fetchBaseQuery({ + baseUrl: "https://hakimhub-api-dev-wtupbmwpnq-uc.a.run.app/api/v1", + // Set the default request method to POST + headers: { + "Content-Type": "application/json", + }, + }), endpoints: (builder) => ({ - getDoctors: builder.query({ - query: (keyword) =>({ url:"search?institutions=false&articles=False", method: 'POST',}), - }), getDoctorProfile: builder.query({ query: (id) => `users/doctorProfile/${id}`, - }), searchDoctors: builder.query({ - query: (keyword) =>({ url:`search?keyword=${keyword}institutions=false&articles=False`, method:'POST'}), + query: (keyword: string) => ({ + url: `search?keyword=${keyword}&institutions=false&articles=False`, + method: "POST", + }), }), }), }); -export const { useGetDoctorsQuery, useGetDoctorProfileQuery, useSearchDoctorsQuery } = doctorsApi; \ No newline at end of file +export const { useGetDoctorProfileQuery, useSearchDoctorsQuery } = doctorsApi; From 0771a2bcbe8fe8f54e6eeb495db93af690e1798f Mon Sep 17 00:00:00 2001 From: Rediet-Ferew Date: Wed, 24 May 2023 12:16:38 +0300 Subject: [PATCH 6/6] fix functionalities --- Web/web_assessment/components/DoctorList.tsx | 8 +++++--- Web/web_assessment/pages/doctors/[id].tsx | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Web/web_assessment/components/DoctorList.tsx b/Web/web_assessment/components/DoctorList.tsx index b88df3a69..0a6dc1efe 100644 --- a/Web/web_assessment/components/DoctorList.tsx +++ b/Web/web_assessment/components/DoctorList.tsx @@ -16,7 +16,6 @@ const DoctorList: React.FC = () => { const handleSearch = (event: React.FormEvent) => { event.preventDefault(); - // Call the search API with the current search term setSearchTerm(event.currentTarget.search.value); }; @@ -46,6 +45,7 @@ const DoctorList: React.FC = () => { {isLoading &&
Loading...
} {isError &&
Error fetching search results
} +
{Array.isArray(doctors) && doctors.map((doctor: any) => ( { id={doctor._id} photoUrl={doctor.photo} name={doctor.fullName} - specialty="pedrasan" - address="addis ababa" + specialty="CardioLogist" + address="Addis Ababa" /> ))} + +
); }; diff --git a/Web/web_assessment/pages/doctors/[id].tsx b/Web/web_assessment/pages/doctors/[id].tsx index 8438306ee..ac93712a9 100644 --- a/Web/web_assessment/pages/doctors/[id].tsx +++ b/Web/web_assessment/pages/doctors/[id].tsx @@ -25,12 +25,12 @@ const DoctorProfile: React.FC = () => { Doctor Profile
-

Dr. John Doe

+

{doctor.fullName}

Specialist in Cardiology

About

-

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod, diam vel tincidunt bibendum, velit sapien luctus velit, vel lacinia velit velit vel velit. Sed euismod, diam vel tincidunt bibendum, velit sapien luctus velit, vel lacinia velit velit vel velit.

+

{doctor.summary}

Education