Skip to content

Commit

Permalink
Opp Carousel Touchups & Goodies (#753)
Browse files Browse the repository at this point in the history
* Organisation admin view tab mobile styling
* Opportunity carousel styling
* Nprogress loader styling
* Update status text
* Cancel submission modal overflow fix
* Custom bounce ease to tailwind config
* Carousel scroll bug fix
  • Loading branch information
Matthew-Baird authored Apr 25, 2024
1 parent be17db2 commit 3171771
Show file tree
Hide file tree
Showing 9 changed files with 202 additions and 83 deletions.
14 changes: 10 additions & 4 deletions src/web/src/components/Carousel/ArrowButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,14 @@ export const PrevButton: React.FC<PropType> = (props) => {

return (
<button
className="btn btn-circle btn-sm transform-gpu cursor-pointer border-[1px] border-purple bg-transparent text-black hover:scale-105 hover:bg-gray"
className="group btn btn-circle btn-sm h-10 w-10 transform-gpu cursor-pointer border-[1.5px] border-purple bg-transparent text-black transition-all duration-500 ease-bounce md:h-8 md:w-8 xl:hover:scale-110 xl:hover:border-purple xl:hover:bg-purple"
type="button"
{...restProps}
>
<svg className="h-[40%] w-[40%]" viewBox="0 0 532 532">
<svg
className="mr-[2px] h-[45%] w-[45%] transform text-purple transition-all duration-500 ease-bounce group-disabled:text-gray xl:group-hover:scale-110 xl:group-hover:text-white"
viewBox="0 0 532 532"
>
<path
fill="currentColor"
d="M355.66 11.354c13.793-13.805 36.208-13.805 50.001 0 13.785 13.804 13.785 36.238 0 50.034L201.22 266l204.442 204.61c13.785 13.805 13.785 36.239 0 50.044-13.793 13.796-36.208 13.796-50.002 0a5994246.277 5994246.277 0 0 0-229.332-229.454 35.065 35.065 0 0 1-10.326-25.126c0-9.2 3.393-18.26 10.326-25.2C172.192 194.973 332.731 34.31 355.66 11.354Z"
Expand All @@ -85,11 +88,14 @@ export const NextButton: React.FC<PropType> = (props) => {

return (
<button
className="btn btn-circle btn-sm transform-gpu cursor-pointer border-[1px] border-purple bg-transparent text-black hover:scale-105 hover:bg-gray"
className="group btn btn-circle btn-sm h-10 w-10 transform-gpu cursor-pointer border-[1.5px] border-purple bg-transparent text-black transition-all duration-500 ease-bounce md:h-8 md:w-8 xl:hover:scale-110 xl:hover:border-purple xl:hover:bg-purple"
type="button"
{...restProps}
>
<svg className="h-[40%] w-[40%]" viewBox="0 0 532 532">
<svg
className="ml-[2px] h-[45%] w-[45%] transform text-purple transition-all duration-500 ease-bounce group-disabled:text-gray xl:group-hover:scale-110 xl:group-hover:text-white"
viewBox="0 0 532 532"
>
<path
fill="currentColor"
d="M176.34 520.646c-13.793 13.805-36.208 13.805-50.001 0-13.785-13.804-13.785-36.238 0-50.034L330.78 266 126.34 61.391c-13.785-13.805-13.785-36.239 0-50.044 13.793-13.796 36.208-13.796 50.002 0 22.928 22.947 206.395 206.507 229.332 229.454a35.065 35.065 0 0 1 10.326 25.126c0 9.2-3.393 18.26-10.326 25.2-45.865 45.901-206.404 206.564-229.332 229.52Z"
Expand Down
2 changes: 1 addition & 1 deletion src/web/src/components/Carousel/SelectedSnapDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const SelectedSnapDisplay: React.FC<{
const { selectedSnap, snapCount } = props;

return (
<div className="flex select-none items-center justify-start font-semibold">
<div className="flex select-none items-center justify-start text-sm font-semibold md:font-normal md:text-gray-dark">
{selectedSnap + 1} / {snapCount}
</div>
);
Expand Down
117 changes: 84 additions & 33 deletions src/web/src/components/Opportunity/OpportunitiesCarousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,57 @@ import {
PrevButton,
NextButton,
} from "../Carousel/ArrowButtons";

const OPTIONS: EmblaOptionsType = {
dragFree: false,
containScroll: "keepSnaps",
watchSlides: true,
watchResize: true,
};
import { useAtomValue } from "jotai";
import { screenWidthAtom } from "~/lib/store";

const OpportunitiesCarousel: React.FC<{
[id: string]: any;
title?: string;
description?: string;
viewAllUrl?: string;
loadData: (startRow: number) => Promise<OpportunitySearchResultsInfo>;
data: OpportunitySearchResultsInfo;
options?: EmblaOptionsType;
}> = (props) => {
const { id, title, viewAllUrl, loadData, data: propData } = props;
const {
id,
title,
description,
viewAllUrl,
loadData,
data: propData,
} = props;
const scrollListenerRef = useRef<() => void>(() => undefined);
const listenForScrollRef = useRef(true);
const hasMoreToLoadRef = useRef(true);
const [slides, setSlides] = useState(propData.items);
const [hasMoreToLoad, setHasMoreToLoad] = useState(true);
const [loadingMore, setLoadingMore] = useState(false);
const screenWidth = useAtomValue(screenWidthAtom);
const [options, setOptions] = useState<EmblaOptionsType>({
dragFree: false,
containScroll: "trimSnaps",
watchSlides: true,
watchResize: true,
align: "start",
});

useEffect(() => {
if (screenWidth < 768) {
setOptions((prevOptions) => ({
...prevOptions,
align: "center",
}));
} else {
setOptions((prevOptions) => ({
...prevOptions,
align: "start",
}));
}
}, [screenWidth]);

const [emblaRef, emblaApi] = useEmblaCarousel({
...OPTIONS,
...options,
watchSlides: (emblaApi) => {
const reloadEmbla = (): void => {
const oldEngine = emblaApi.internalEngine();
Expand Down Expand Up @@ -156,22 +181,44 @@ const OpportunitiesCarousel: React.FC<{
}, [hasMoreToLoad]);

return (
<div className="mb-12 md:mb-8">
<div className="mb-12 md:mb-20">
<div className="mb-2 flex flex-col gap-6">
<div className="flex max-w-full flex-row px-4 md:max-w-7xl md:px-0">
<div className="flex flex-grow">
<div className="flex flex-grow flex-col">
<div className="overflow-hidden text-ellipsis whitespace-nowrap text-xl font-semibold text-black md:max-w-[800px]">
{title}
</div>
<div className="text-gray-dark">{description}</div>
</div>

<div className="flex items-center gap-4">
{snapCount > 1 && selectedSnap < snapCount && (
<div className="flex items-center">
<div className="hidden w-full gap-4 md:flex">
<SelectedSnapDisplay
selectedSnap={selectedSnap}
snapCount={propData.totalCount ?? snapCount}
/>
<PrevButton
onClick={onPrevButtonClick}
disabled={prevBtnDisabled}
/>
<NextButton
onClick={onNextButtonClick}
disabled={nextBtnDisabled}
/>
</div>
</div>
)}
{viewAllUrl && (
<Link
href={viewAllUrl}
className="flex w-14 select-none whitespace-nowrap border-b-2 border-transparent text-center text-sm tracking-wide text-gray-dark duration-300 xl:hover:border-purple xl:hover:text-purple"
>
View All
</Link>
)}
</div>
{viewAllUrl && (
<Link
href={viewAllUrl}
className="my-auto items-end text-sm text-gray-dark"
>
View all
</Link>
)}
</div>
{/* {slidePercentage <= 0 && (
<div className="flex items-center justify-center">
Expand Down Expand Up @@ -206,20 +253,24 @@ const OpportunitiesCarousel: React.FC<{
</div>

{snapCount > 1 && selectedSnap < snapCount && (
<div className="my-2 mt-0 flex w-full place-content-start md:mb-10">
<div className="mx-auto flex scale-100 justify-center gap-4 md:mx-0 md:mr-auto md:scale-[0.85] md:justify-start md:gap-2">
<SelectedSnapDisplay
selectedSnap={selectedSnap}
snapCount={propData.totalCount ?? snapCount}
/>
<PrevButton
onClick={onPrevButtonClick}
disabled={prevBtnDisabled}
/>
<NextButton
onClick={onNextButtonClick}
disabled={nextBtnDisabled}
/>
<div className="my-2 mt-2 flex w-full place-content-start md:mb-10 md:mt-1">
<div className="mx-auto flex w-full justify-center gap-4 md:mx-0 md:mr-auto md:justify-start md:gap-6">
{screenWidth < 768 && (
<>
<PrevButton
onClick={onPrevButtonClick}
disabled={prevBtnDisabled}
/>
<SelectedSnapDisplay
selectedSnap={selectedSnap}
snapCount={propData.totalCount ?? snapCount}
/>
<NextButton
onClick={onNextButtonClick}
disabled={nextBtnDisabled}
/>
</>
)}
</div>
</div>
)}
Expand Down
14 changes: 8 additions & 6 deletions src/web/src/components/Opportunity/OpportunityPublicSmall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import iconUser from "public/images/icon-user.svg";
import iconZlto from "public/images/icon-zlto.svg";
import Moment from "react-moment";
import { DATE_FORMAT_HUMAN } from "~/lib/constants";
import { IoMdPause, IoMdPlay, IoMdClose } from "react-icons/io";
import { IoMdCalendar, IoMdPlay, IoMdCloudUpload } from "react-icons/io";
import { AvatarImage } from "../AvatarImage";
interface InputProps {
data: OpportunityInfo;
Expand Down Expand Up @@ -112,22 +112,24 @@ const OpportunityPublicSmallComponent: React.FC<InputProps> = ({ data }) => {
<>
{new Date(data.dateStart) > new Date() && (
<div className="badge bg-yellow-tint text-yellow">
<IoMdPause />
<p className="ml-1">Not started</p>
<IoMdCalendar className="h-4 w-4" />
<Moment format={DATE_FORMAT_HUMAN} utc={true} className="ml-1">
{data.dateStart}
</Moment>
</div>
)}
{new Date(data.dateStart) < new Date() && (
<div className="badge bg-purple-tint text-purple-shade">
<IoMdPlay />
<span className="ml-1">Started</span>
<span className="ml-1">Ongoing</span>
</div>
)}
</>
)}
{data.status == "Expired" && (
<div className="badge bg-red-100 text-error">
<IoMdClose className="h-4 w-4" />
<span className="ml-1">Expired</span>
<IoMdCloudUpload className="h-4 w-4" />
<span className="ml-1">Upload Only</span>
</div>
)}
</div>
Expand Down
8 changes: 6 additions & 2 deletions src/web/src/pages/opportunities/[[...query]]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,8 @@ const Opportunities: NextPageWithLayout<{

const lookups_publishedStates: SelectOption[] = [
{ value: "0", label: "Not started" },
{ value: "1", label: "Active" },
...(session ? [{ value: "2", label: "Expired" }] : []), // logged in users can see expired
{ value: "1", label: "Ongoing" },
...(session ? [{ value: "2", label: "Upload Only" }] : []), // logged in users can see expired
];

// get filter parameters from route
Expand Down Expand Up @@ -886,6 +886,7 @@ const Opportunities: NextPageWithLayout<{
<OpportunitiesCarousel
id={`opportunities_trending`}
title="Trending 🔥"
description="The most viewed opportunities"
data={opportunities_trending}
loadData={loadDataTrending}
viewAllUrl="/opportunities?mostViewed=true"
Expand All @@ -897,6 +898,7 @@ const Opportunities: NextPageWithLayout<{
<OpportunitiesCarousel
id={`opportunities_learning`}
title="Learning Courses 📚"
description="Discover exciting online courses"
data={opportunities_learning}
loadData={loadDataLearning}
viewAllUrl="/opportunities?types=Learning"
Expand All @@ -908,6 +910,7 @@ const Opportunities: NextPageWithLayout<{
<OpportunitiesCarousel
id={`opportunities_tasks`}
title="Impact Tasks ⚡"
description="Contribute to real-world projects"
data={opportunities_tasks}
loadData={loadDataTasks}
viewAllUrl="/opportunities?types=Task"
Expand All @@ -919,6 +922,7 @@ const Opportunities: NextPageWithLayout<{
<OpportunitiesCarousel
id={`opportunities_allOpportunities`}
title="All Opportunities"
description="Explore all available opportunities"
data={opportunities_allOpportunities}
loadData={loadDataOpportunities}
viewAllUrl="/opportunities?page=1"
Expand Down
21 changes: 14 additions & 7 deletions src/web/src/pages/opportunities/[opportunityId]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ import {
IoMdClose,
IoMdFingerPrint,
IoMdArrowRoundBack,
IoMdPause,
IoMdPlay,
IoMdBookmark,
IoMdPerson,
IoIosBook,
IoMdCalendar,
IoMdCloudUpload,
} from "react-icons/io";
import type { NextPageWithLayout } from "~/pages/_app";
import ReactModal from "react-modal";
Expand Down Expand Up @@ -645,7 +646,7 @@ const OpportunityDetails: NextPageWithLayout<{
onRequestClose={() => {
setCancelOpportunityDialogVisible(false);
}}
className={`fixed bottom-0 left-0 right-0 top-0 flex-grow overflow-y-scroll bg-white animate-in fade-in md:m-auto md:max-h-[450px] md:w-[600px] md:overflow-y-clip md:rounded-3xl`}
className={`fixed bottom-0 left-0 right-0 top-0 flex-grow overflow-y-scroll bg-white animate-in fade-in md:m-auto md:max-h-[450px] md:w-[600px] md:overflow-y-hidden md:rounded-3xl`}
portalClassName={"fixed z-40"}
overlayClassName="fixed inset-0 bg-overlay"
>
Expand Down Expand Up @@ -776,22 +777,28 @@ const OpportunityDetails: NextPageWithLayout<{
<>
{new Date(opportunity.dateStart) > new Date() && (
<div className="badge bg-yellow-tint text-yellow">
<IoMdPause />
<p className="ml-1">Not started</p>
<IoMdCalendar className="h-4 w-4" />
<Moment
format={DATE_FORMAT_HUMAN}
utc={true}
className="ml-1"
>
{opportunity.dateStart}
</Moment>
</div>
)}
{new Date(opportunity.dateStart) < new Date() && (
<div className="badge bg-purple-tint text-purple-shade">
<IoMdPlay />
<span className="ml-1">Started</span>
<span className="ml-1">Ongoing</span>
</div>
)}
</>
)}
{opportunity?.status == "Expired" && (
<div className="badge bg-red-100 text-error">
<IoMdClose className="h-4 w-4" />
<span className="ml-1">Expired</span>
<IoMdCloudUpload className="h-4 w-4" />
<span className="ml-1">Upload Only</span>
</div>
)}
</div>
Expand Down
Loading

0 comments on commit 3171771

Please sign in to comment.