Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BI-46: Fetch University Data from MongoDB #22

Merged
merged 44 commits into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
e58b6ec
search-bar feature added
meenalnimje Sep 27, 2023
7987311
suggested changes added
meenalnimje Sep 29, 2023
36cf4e0
2nd review
meenalnimje Oct 2, 2023
6aa2e65
changes after 2nd review
meenalnimje Oct 2, 2023
f118309
merge commit fix
meenalnimje Oct 3, 2023
6f391ae
prettier formate
meenalnimje Oct 3, 2023
7e366c8
changes in stories
meenalnimje Oct 3, 2023
58db507
export removed
meenalnimje Oct 3, 2023
dcb4c1c
suggested changes made
meenalnimje Oct 5, 2023
b4d2a70
storybook for navbar and footer is added
meenalnimje Oct 19, 2023
e3c349b
Merge branch 'main' into BI-28
meenalnimje Oct 19, 2023
11672f4
footer position changed from sticky to relative
meenalnimje Oct 20, 2023
0914a02
Merge branch 'BI-28' of https://github.com/BacPacNet/web-app-client i…
meenalnimje Oct 20, 2023
4d6afdd
css changes in footer
meenalnimje Oct 20, 2023
023d0ca
change in css of footer
meenalnimje Oct 20, 2023
d4ad1dd
change-1:-spacing,footer title resolved and font style corrected
meenalnimje Oct 20, 2023
82f3a81
design changed in navbar acc. to design team
meenalnimje Oct 22, 2023
49e04db
navbarlinks colour changed to black
meenalnimje Oct 23, 2023
5c65285
error resolved
meenalnimje Oct 23, 2023
ca2c3c0
homepage storybook added
meenalnimje Oct 23, 2023
29db724
changes based on chromatic comments
meenalnimje Oct 23, 2023
2232ebe
size of navbar and footer decresed
meenalnimje Oct 25, 2023
134c694
alignment correction
meenalnimje Oct 25, 2023
b32c347
another text alignment correction
meenalnimje Oct 25, 2023
ca19aa1
navbar alignment changes
meenalnimje Oct 25, 2023
55a9e20
navbar logo size fixed
meenalnimje Oct 26, 2023
b1e7175
searchbar element visibility corrected && other elemnts of searchpage…
meenalnimje Oct 26, 2023
5bf66fa
design and responsiveness added
meenalnimje Oct 30, 2023
b56362d
color added in specific texts
meenalnimje Nov 29, 2023
2e35b7e
after review suggested changes made
meenalnimje Dec 11, 2023
0e955e0
fetching data from mongodb query added
meenalnimje Dec 19, 2023
ab6e00a
change for BI-28
meenalnimje Dec 19, 2023
5ae6ff6
BI-28
meenalnimje Dec 19, 2023
aafb764
query for fetching data from mongo is added, testing is left
meenalnimje Dec 19, 2023
e870cb0
error in workflow checks and tests resolved
meenalnimje Dec 19, 2023
13439dc
storybook error solved
meenalnimje Dec 19, 2023
22edb7d
error in workflow resolved
meenalnimje Dec 19, 2023
45870d4
workflow error is resolved
meenalnimje Dec 19, 2023
ec3b57b
testing code for fetching college data is added
meenalnimje Dec 21, 2023
b3bd827
fixing in searching algorithm due to query
meenalnimje Dec 21, 2023
958af65
fixes to solve workflow error
meenalnimje Dec 21, 2023
d77d523
testing code fixed
meenalnimje Dec 21, 2023
0ae929f
some error fixed
meenalnimje Dec 21, 2023
0c7e04f
Bi 46 review 1 (#25)
meenalnimje Feb 8, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
/** @type {import('next').NextConfig} */
const nextConfig = {}
require('dotenv').config();
const nextConfig = {
async headers() {
return [
{
// matching all API routes
source: "/api/:path*",
headers: [
{ key: "Access-Control-Allow-Credentials", value: "true" },
{ key: "Access-Control-Allow-Origin", value: "*" },
{ key: "Access-Control-Allow-Methods", value: "GET,OPTIONS,PATCH,DELETE,POST,PUT" },
{ key: "Access-Control-Allow-Headers", value: "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" },
]
}
]
}
}

module.exports = nextConfig
702 changes: 430 additions & 272 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,14 @@
"chromatic": "chromatic --exit-zero-on-changes"
},
"dependencies": {
"@apollo/client": "^3.8.8",
"@apollo/server": "^4.9.5",
"@as-integrations/next": "^2.0.2",
"autoprefixer": "10.4.16",
"cors": "^2.8.5",
"cross-fetch": "^4.0.0",
"dotenv": "^16.3.1",
"graphql": "^16.8.1",
"graphql-tag": "^2.12.6",
"match-sorter": "^6.3.1",
"mongodb": "^6.1.0",
Expand Down
7 changes: 4 additions & 3 deletions src/__tests__/home.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { render, screen } from '@testing-library/react'
import Home from '../app/page.js'
import SearchBar from '@/components/SearchBar.js'
import '@testing-library/jest-dom'

import { render, screen } from '@testing-library/react'

import SearchBar from '../components/SearchBar'

it('renders a search box', () => {
const { getByPlaceholderText } = render(<SearchBar />)

Expand Down
57 changes: 57 additions & 0 deletions src/__tests__/query.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import '@testing-library/jest-dom'

import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client'

import fetch from 'cross-fetch'
import { gql } from '@apollo/client'

const query = gql`
query getUniversityList {
universityList {
id
name
score
country
city
}
}
`

let uri = 'https://web-app-client-b69l4yjrq-bacpacs-projects.vercel.app/api/graphql'
console.log('GraphQL URI in tests:', uri)
const client = new ApolloClient({
link: new HttpLink({ uri, fetch }),
cache: new InMemoryCache(),
})
// test to check the data is not empty
test('the data is of college', async () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: If you want to try the describe statement, give it a shot.

You can fetch the data inside the describe and use the same variable inside both the tests. Here's an example (I copied it from ChatGPT):

describe('example describe block', () => {
  let fetchedData;

  beforeAll(async () => {
    // Fetch data (e.g., from an API)
    fetchedData = await fetchData();
  });

  test('test case 1', () => {
    // Use fetchedData in the first test
    expect(fetchedData).toBeDefined();
    expect(fetchedData.length).toBeGreaterThan(0);
  });

  test('test case 2', () => {
    // Reuse fetchedData in the second test
    expect(fetchedData).toHaveProperty('property1');
    expect(fetchedData).toHaveProperty('property2');
  });
});

const result = await client.query({ query })

expect(result?.data).not.toBeNull()
expect(result?.data).toHaveProperty('universityList')
expect(result?.data?.universityList).toBeInstanceOf(Array)
expect(result?.data?.universityList?.length).toBeGreaterThan(0)
})
// test to check the format of data recived by the query
test('the data has specific properties', async () => {
const result = await client.query({ query })

result?.data?.universityList?.forEach((college) => {
// check for id property
expect(college).toHaveProperty('id')
expect(college?.id).not.toBeNull()
expect(typeof college?.id).toBe('string')
// check for name property
expect(college).toHaveProperty('name')
expect(college?.name).not.toBeNull()
expect(typeof college?.name).toBe('string')
// check for score property
expect(college).toHaveProperty('score')
expect(college?.score).not.toBeNull()
expect(typeof college?.score).toBe('string')
// check for country property
expect(college).toHaveProperty('country')
expect(college?.country).not.toBeNull()
expect(typeof college?.country).toBe('string')
})
})
25 changes: 25 additions & 0 deletions src/__tests__/searchAlgorithm.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import searchAlgorithm from '../utils/searchAlgorithm'
describe('searchAlgorithm', () => {
const colleges = [{ name: 'Massachusetts Institute of Technology (MIT)', country: 'United States', city: 'Cambridge' }]
it('returns filtered results when input and data are provided', () => {
const input = 'mass'

const result = searchAlgorithm(input, colleges)

expect(result).toEqual([{ name: 'Massachusetts Institute of Technology (MIT)', country: 'United States', city: 'Cambridge' }])
})
it('returns an empty array when either input is not provided', () => {
const input = ''

const result = searchAlgorithm(input, colleges)

expect(result).toEqual([])
})
it('returns an empty array when either input doesnot match with the college name,city or country', () => {
const input = 'xyw'

const result = searchAlgorithm(input, colleges)

expect(result).toEqual([])
})
})
37 changes: 29 additions & 8 deletions src/app/api/graphql/route.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,62 @@
import { startServerAndCreateNextHandler } from '@as-integrations/next'
import { ApolloServer } from '@apollo/server'
import { ApolloServerPluginLandingPageLocalDefault, ApolloServerPluginLandingPageProductionDefault } from '@apollo/server/plugin/landingPage/default'
import { gql } from 'graphql-tag'

import { ApolloServer } from '@apollo/server'
import { MongoClient } from 'mongodb'
import { gql } from 'graphql-tag'
import { startServerAndCreateNextHandler } from '@as-integrations/next'

// The connection string for mongodb connection.
const uri = process.env.MONGODB_URI || ''
const uri = process.env.MONGODB_URI
const client = new MongoClient(uri)

async function getUniversityName(id) {
try {
const database = client.db('bacpac')
const universities = database.collection('universities')
const university = await universities.findOne({ id })
return university.name
const universityList = await universities.findOne({ id })
return universityList.name
} catch (error) {
console.log(error)
}
}
async function getUniversityList() {
try {
const database = client.db('bacpac')
const universities = database.collection('universities')
const universityList = await universities.find().toArray()
return universityList
} catch (error) {
console.log('this is error from get all unversity list side', error)
}
}

const resolvers = {
Query: {
university_name: async (_, args) => {
return await getUniversityName(args.id)
},
universityList: () => {
return getUniversityList()
},
},
}

const typeDefs = gql`
type Query {
university_name(id: ID!): String
universityList: [universityInfo]
}
type universityInfo {
id: String
name: String
score: String
country: String
city: String
}
`

let plugins = []
const graphQLref = process.env.GRAPHQL_REF || ''
const graphQLref = process.env.GRAPHQL_REF
//Next.js auto assigns NODE_ENV value as development for 'next dev' command, and production for other commands
if (process.env.NODE_ENV === 'production') {
plugins = [
Expand All @@ -52,7 +74,6 @@ const server = new ApolloServer({
typeDefs,
plugins,
})

const handler = startServerAndCreateNextHandler(server)

//Exports the handler function to be used as a Next.js API route handler.
Expand Down
1 change: 1 addition & 0 deletions src/app/components/CollegeResult.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Link from 'next/link'

function CollegeResult(props) {
return (
<div className="mb-3.5">
Expand Down
40 changes: 21 additions & 19 deletions src/app/page.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,44 @@
'use client'

import { AiOutlineSearch } from 'react-icons/ai'
import { useEffect, useState } from 'react'

import { BsStars } from 'react-icons/bs'
import CollegeResult from './components/CollegeResult'
import Footer from './components/Footer/Footer'
import Image from 'next/image'
import Link from 'next/link'
import Navbar from './components/Navbar/Navbar'
import SearchBar from '../components/SearchBar'
import bacpacTitle from '../assets/bacpacTitle.png'
import bookImgLogo from '../assets/bookimg.png'
import client from '../client'
import discord from '../assets/discordLog.png'
import universityData from '../../data/university_data'
import { useState } from 'react'
import SearchBar from '../components/SearchBar'
import { query } from '../queries/queries'

export default function Home() {
const [open, setOpen] = useState(false)
const [searchData, setSearchData] = useState([])
function handleSearch(e) {
let input = e.target.value.toLowerCase()
const filterData = universityData
.filter((item) => {
let collegeName = item.name.toLowerCase()
let collegeAddress = item.address.toLowerCase()
return collegeName.includes(input) || collegeAddress.includes(input)
})
.sort((a, b) => b.score - a.score)
setOpen(input.length !== 0)
setSearchData(filterData)
const [universityData, setUniversityData] = useState(null)
const [loading, setLoading] = useState(false)
async function fetchData() {
try {
setLoading(true)
const result = await client.query({ query })
setUniversityData(result?.data?.universityList)
} catch (error) {
console.log('Error fetching data:', error)
} finally {
setLoading(false)
}
}
useEffect(() => {
fetchData()
}, [])
return (
<div className="home">
<Navbar />
<main className="flex h-full w-full flex-col items-center justify-start max-h-full bg-[#ffffff]">
<div className="text-9xl font-bold mt-28">
<Image src={bacpacTitle} alt="BACPAC" className="w-full h-full" />
</div>
<SearchBar data={universityData} />
<SearchBar data={universityData} loading={loading} />
<div className="login-part w-5/12 mt-24 flex flex-col items-center">
<div className="flex items-center mb-5 w-full justify-center">
<BsStars className="text-[#6744FF] text-4xl -ml-3 center" />
Expand Down
12 changes: 12 additions & 0 deletions src/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client'

import fetch from 'cross-fetch'

let uri = '/api/graphql'
console.log('GraphQL URI in Client:', uri)
const client = new ApolloClient({
link: new HttpLink({ uri, fetch }),
cache: new InMemoryCache(),
})

export default client
16 changes: 7 additions & 9 deletions src/components/SearchBar.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
import { useState } from 'react'
import { AiOutlineSearch } from 'react-icons/ai'
import CollegeResult from '../app/components/CollegeResult'
import searchAlgorithm from '@/utils/searchAlgorithm'
const SearchBar = ({ data }) => {
import searchAlgorithm from '../utils/searchAlgorithm'
import { useState } from 'react'

const SearchBar = ({ data, loading }) => {
const [open, setOpen] = useState(false)
const [filterData, setFilterData] = useState([])

const handleSearch = (e) => {
let input = e.target.value.trim().toLowerCase()
const filterData = searchAlgorithm(input)
const filterData = searchAlgorithm(input, data).sort((a, b) => b.score - a.score)
setOpen(input.length !== 0)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit skeptical with the sort() here. Maybe we can use it inside the search algorithm, in case that's the case, let's communicate with @ayushtiwari110 regarding this, we might need to write a new test for it, that'll drive this functionality.

setFilterData(filterData)
}

let searchResults = filterData?.map((item, index) => <CollegeResult info={item} serialNo={index} key={index} />)

if (searchResults.length === 0) searchResults = <div>No results found</div>

if (!loading && searchResults.length === 0) searchResults = <div>No results found</div>
if (loading) searchResults = <div>Loading....</div>
return (
<div className="search-box mt-4 w-5/12 h-12 rounded-2xl">
<div className="search-icon w-12 absolute h-12 flex justify-center items-center">
Expand Down
12 changes: 12 additions & 0 deletions src/queries/queries.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { gql } from '@apollo/client'
export const query = gql`
query getUniversityList {
universityList {
id
name
score
country
city
}
}
`
9 changes: 6 additions & 3 deletions src/utils/searchAlgorithm.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { matchSorter } from 'match-sorter'
import colleges from '../../data/university_data.json'

const searchAlgorithm = (input) => {
return matchSorter(colleges, input, { keys: ['name', 'address'] })
const searchAlgorithm = (input, data) => {
if (input && data) {
return matchSorter(data, input, { keys: ['name', 'country', 'city'] })
} else {
return []
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I checked in the codecov, it turns out, this line wasn't tested at the moment. So, let's write a simple test for it, which can be triggered by empty data.

}
}
export default searchAlgorithm
Loading