Skip to content

Commit

Permalink
university filter screen and university info screen
Browse files Browse the repository at this point in the history
  • Loading branch information
Aamil13 committed Dec 22, 2024
1 parent a6cebfb commit a698535
Show file tree
Hide file tree
Showing 10 changed files with 521 additions and 23 deletions.
15 changes: 14 additions & 1 deletion next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,21 @@ const withPWA = require("next-pwa")({
// Next.js configuration
const nextConfig = {
// Allow images from external domains
// images: {
// domains: ['cdn.pixabay.com', "res.cloudinary.com", "upload.wikimedia.org", 'www.servizisegreti.com',"saig.physics.ualberta.ca"],
// },

images: {
domains: ['cdn.pixabay.com', "res.cloudinary.com", "upload.wikimedia.org", 'www.servizisegreti.com',"saig.physics.ualberta.ca"],
remotePatterns: [
{
protocol: 'https',
hostname: '**', // Accepts all domains
},
{
protocol: 'http',
hostname: '**', // Accepts all domains
},
],
},

// Custom headers for API routes
Expand Down
3 changes: 2 additions & 1 deletion src/app/discover/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import DiscoverContainer from '@/components/organisms/DiscoverContainer'
import React from 'react'

function Discover() {
return <div>Discover</div>
return <DiscoverContainer />
}

export default Discover
142 changes: 129 additions & 13 deletions src/app/university/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,154 @@
'use client'
import Buttons from '@/components/atoms/Buttons'
import Loading from '@/components/atoms/Loading'
import { useUniversitySearch, useUniversitySearchByName } from '@/services/universitySearch'
import { UniversityInfo } from '@/types/University'
import ImagePlaceholder from '@assets/unibuzz-orange.png'
import { useUniversitySearchByName } from '@/services/universitySearch'
import Image from 'next/image'
import { useParams } from 'next/navigation'
import { MdEmail } from 'react-icons/md'
import React, { useState } from 'react'
import { FaPhoneAlt } from 'react-icons/fa'
import { MdFax } from 'react-icons/md'
import { IoIosLink } from 'react-icons/io'
import { PiBuildingsFill } from 'react-icons/pi'
import { BsClockFill } from 'react-icons/bs'
import universityPlaceholder from '@assets/university_placeholder.jpg'
import universityLogoPlaceholder from '@assets/unibuzz_rounded.svg'
import { IconType } from 'react-icons/lib'

import React, { useEffect } from 'react'
const UniversityCard = ({ icon: Icon, title, info }: { icon: IconType; title: string; info: string }) => (
<div>
<p className="text-primary-700 flex gap-1 items-center font-bold">
<Icon size={20} />
{title}
</p>
<p className={`text-neutral-700 text-xs line-clamp-6`}>{info || 'Not available'}</p>
</div>
)

export default function UniversityProfile() {
const params = useParams()
const { id: universityName } = params
const { data: university, isLoading: isUniversityLoading } = useUniversitySearchByName(universityName as string)

const [imageSrc, setImageSrc] = useState(university?.images[0] || universityPlaceholder)
const [logoSrc, setLogoSrc] = useState(university?.logos?.[0] || universityLogoPlaceholder)

if (isUniversityLoading) return <Loading />

const contactData = [
{
icon: MdEmail,
title: 'Email',
info: university.wikiInfoBox?.email,
},
{
icon: FaPhoneAlt,
title: 'Phone',
info: university.collegeBoardInfo?.['Phone number'],
},
{
icon: MdFax,
title: 'Fax',
info: university.wikiInfoBox?.fax,
},
]

const additionalData = [
{
icon: IoIosLink,
title: 'Link',
info: university.collegeBoardInfo?.website,
},
{
icon: PiBuildingsFill,
title: 'Address',
info: university.collegeBoardInfo?.Location,
},
{
icon: BsClockFill,
title: 'Office Hours',
info: university.wikiInfoBox?.['Office Hours'] || 'Monday to Friday 9:00 am - 12:00 p.m. and 1:00 p.m - 5:00 p.m',
},
]

return (
<div className="p-28 ">
<div className="flex gap-16">
<div className="flex-1">
<div className="p-28 flex flex-col gap-4 max-sm:px-4">
<div className="flex gap-16 max-lg:flex-col-reverse">
<div className="flex flex-col gap-5">
<div className="flex items-center gap-9 py-4">
<div className="flex justify-center items-center p-6 drop-shadow-lg rounded-full bg-white">
<img
<Image
width={46}
height={46}
src={university?.logos?.[0] || (ImagePlaceholder as unknown as string)}
src={logoSrc}
alt="logo"
className="max-w-full max-h-40 object-contain"
onError={() => setLogoSrc(universityLogoPlaceholder)}
/>
</div>

<p className="text-neutral-900 text-lg font-extrabold">{university?.name}</p>
<p className="text-neutral-900 text-lg font-extrabold w-96 max-xl:w-60 max-xl:text-[24px] max-lg:w-full">{university?.name}</p>
</div>
<p className={`text-neutral-500 text-xs line-clamp-6`}>{university?.topUniInfo?.about}</p>
<p className={`text-neutral-500 text-xs line-clamp-6 max-w-lg`}>{university?.topUniInfo?.about || 'Not Available'}</p>
{university?.isCommunityCreated ? <Buttons className="w-max">Join Community</Buttons> : <Buttons className="w-max">Endorse</Buttons>}
</div>
<div className=" flex justify-center w-8/12 max-lg:w-full max-sm:items-center">
<Image
width={400}
height={600}
className="rounded-lg h-96 object-cover w-10/12 max-lg:w-full"
src={imageSrc}
alt="university_image"
onError={() => setImageSrc(universityPlaceholder)}
/>
</div>
<div className="flex-1 flex justify-center">
<img className="rounded-lg max-w-full object-contain" src={university?.images[0]} alt="university_image" />
</div>
{/* //overview */}
<div className="flex flex-col gap-4">
<p className="text-neutral-900 text-base font-extrabold w-96">Overview</p>
<div className="flex flex-col gap-4">
<p className={`text-neutral-500 text-xs line-clamp-6 `}>
Loremium University boasts a world-class faculty, many of whom are leaders in their respective fields. The university’s commitment to
innovation and research has led to groundbreaking discoveries and advancements, particularly in the realms of biotechnology, environmental
science, and digital arts. The state-of-the-art laboratories and creative studios provide students with the resources and inspiration
needed to push the boundaries of knowledge and creativity.
</p>
<p className={`text-neutral-500 text-xs line-clamp-6 `}>
In addition to its scientific prowess, Loremium University is a thriving cultural hub. The university’s School of Arts is renowned for its
avant-garde approach to art and design, producing graduates who have gone on to achieve international acclaim. Regular exhibitions,
performances, and lectures by visiting artists and scholars enrich the campus life and foster a dynamic exchange of ideas.
</p>
<p className={`text-neutral-500 text-xs line-clamp-6 `}>
Loremium University is a magnet for students from around the globe, drawn by its stellar reputation and welcoming atmosphere. The
university’s diverse student body, hailing from over 80 countries, creates a rich tapestry of cultures and perspectives. Dedicated support
services ensure that international students feel at home, making their transition to life in Loremium seamless and enjoyable.
</p>
</div>
</div>
{/* //contact */}
<div className="flex flex-col gap-4 mt-4">
<p className="text-neutral-900 text-base font-extrabold w-96">Contact Info</p>
<div className="flex justify-between gap-20 max-sm:flex-col max-sm:gap-5">
<div className="bg-neutral-200 py-2 px-4 w-full h-44 rounded-lg flex flex-col justify-between">
{contactData.map((item, index) => (
<UniversityCard key={index} icon={item.icon} title={item.title} info={item.info} />
))}
</div>
<div className="bg-neutral-200 py-2 px-4 w-full h-44 rounded-lg flex flex-col justify-between">
{additionalData.map((item, index) => (
<UniversityCard key={index} icon={item.icon} title={item.title} info={item.info} />
))}
</div>
</div>
</div>
{/* //contact */}
<div className="flex flex-col gap-4 mt-4">
<p className="text-neutral-900 text-base font-extrabold w-96">Reviews</p>
<div className="flex flex-col gap-4 items-center justify-center h-60">
<p className="text-neutral-900 text-base font-extrabold ">Reviews are coming soon!</p>
<p className={`text-neutral-700 text-xs line-clamp-6 max-w-lg text-center `}>
This feature is under construction. If you would like to have it sooner send us some feedback!
</p>
</div>
</div>
</div>
Expand Down
113 changes: 107 additions & 6 deletions src/components/atoms/SelectDropdown/SelectDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,100 @@ const motionStyle = {
exit: { opacity: 0, y: '-10%', transition: { duration: '0.35' } },
transition: { type: 'spring', stiffness: '100', duration: '0.75' },
}
// const SelectDropdown = ({ options, onChange, value, placeholder, icon, search = false, err, showIcon = false }: SelectDropdownProps) => {
// const [show, setShow] = useState(false)
// const dropdownRef = useRef<HTMLDivElement>(null)
// const [filteredOptions, setFilteredOptions] = useState(options)
// const searchRef = useRef<HTMLInputElement>(null)

// const handleSelect = (optionValue: string) => {
// onChange(optionValue)
// setShow(false)
// }

// const handleSearch = () => {
// const searchValue = searchRef.current?.value.toLowerCase() || ''
// setFilteredOptions(searchValue === '' ? options : options.filter((option: string) => option.toLowerCase().includes(searchValue)))
// }

// useEffect(() => {
// const handleClickOutside = (event: MouseEvent) => {
// if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
// setShow(false)
// }
// }

// document.addEventListener('mousedown', handleClickOutside)

// return () => {
// document.removeEventListener('mousedown', handleClickOutside)
// }
// }, [])

// return (
// <motion.div ref={dropdownRef} className="relative">
// <div
// onClick={() => setShow(!show)}
// className={`${
// err ? 'border-red-400' : 'border-neutral-200'
// } flex justify-between items-center py-2 px-3 border focus:ring-2 rounded-lg drop-shadow-sm text-neutral-400 outline-none`}
// >
// <p className={`${value ? 'text-neutral-900' : 'text-neutral-400'} text-2xs`}> {value || placeholder}</p>
// <div>
// {icon == 'single' ? (
// <IoIosArrowDown />
// ) : (
// <div className="flex flex-col text-xs">
// <IoIosArrowUp />
// <IoIosArrowDown />
// </div>
// )}
// </div>
// </div>
// <AnimatePresence>
// {show && (
// <motion.div
// className={`flex flex-col custom-scrollbar ${
// !showIcon ? 'gap-2 w-full p-2' : 'gap-1 p-1'
// } absolute right-0 bg-white shadow-lg border border-neutral-200 rounded-lg z-10 max-h-52 w-52 overflow-y-auto`}
// {...motionStyle}
// >
// {search && (
// <input
// type="text"
// className="py-2 px-3 border focus:ring-2 rounded-lg drop-shadow-sm border-neutral-200 text-neutral-700 h-10 outline-none"
// ref={searchRef}
// placeholder="Search..."
// onChange={handleSearch}
// />
// )}
// {filteredOptions?.length > 0 ? (
// filteredOptions?.map((item: string, key: number) => {
// const IconComponent = icons[key % icons.length]
// return (
// <div
// className={`${
// key === 0 ? '' : 'border-t'
// } flex gap-2 items-center border-neutral-300 text-2xs text-neutral-900 p-1 cursor-pointer hover:bg-gray-200`}
// onClick={() => handleSelect(item)}
// key={key}
// >
// {showIcon && <IconComponent size={16} className="text-neutral-900" />}
// <p>{item}</p>
// </div>
// )
// })
// ) : (
// <p className="text-neutral-500 p-2">No results found</p>
// )}
// </motion.div>
// )}
// </AnimatePresence>
// </motion.div>
// )
// }

// export default SelectDropdown
const SelectDropdown = ({ options, onChange, value, placeholder, icon, search = false, err, showIcon = false }: SelectDropdownProps) => {
const [show, setShow] = useState(false)
const dropdownRef = useRef<HTMLDivElement>(null)
Expand Down Expand Up @@ -55,17 +149,25 @@ const SelectDropdown = ({ options, onChange, value, placeholder, icon, search =
}
}, [])

const toggleDropdown = () => {
if (!show) {
setFilteredOptions(options)
if (searchRef.current) searchRef.current.value = ''
}
setShow((prevShow) => !prevShow)
}

return (
<motion.div ref={dropdownRef} className="relative">
<div
onClick={() => setShow(!show)}
onClick={toggleDropdown}
className={`${
err ? 'border-red-400' : 'border-neutral-200'
} flex justify-between items-center py-2 px-3 border focus:ring-2 rounded-lg drop-shadow-sm text-neutral-400 outline-none`}
>
<p className={`${value ? 'text-neutral-900' : 'text-neutral-400'} text-2xs`}> {value || placeholder}</p>
<div>
{icon == 'single' ? (
{icon === 'single' ? (
<IoIosArrowDown />
) : (
<div className="flex flex-col text-xs">
Expand All @@ -78,9 +180,9 @@ const SelectDropdown = ({ options, onChange, value, placeholder, icon, search =
<AnimatePresence>
{show && (
<motion.div
className={`flex flex-col custom-scrollbar ${
className={`flex flex-col custom-scrollbar ${
!showIcon ? 'gap-2 w-full p-2' : 'gap-1 p-1'
} absolute right-0 bg-white shadow-lg border border-neutral-200 rounded-lg z-10 max-h-52 w-52 overflow-y-auto`}
} absolute right-0 bg-white shadow-lg border border-neutral-200 rounded-lg z-10 max-h-52 w-52 overflow-y-auto`}
{...motionStyle}
>
{search && (
Expand All @@ -93,7 +195,7 @@ const SelectDropdown = ({ options, onChange, value, placeholder, icon, search =
/>
)}
{filteredOptions?.length > 0 ? (
filteredOptions?.map((item: string, key: number) => {
filteredOptions.map((item: string, key: number) => {
const IconComponent = icons[key % icons.length]
return (
<div
Expand All @@ -117,5 +219,4 @@ const SelectDropdown = ({ options, onChange, value, placeholder, icon, search =
</motion.div>
)
}

export default SelectDropdown
Loading

0 comments on commit a698535

Please sign in to comment.