Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
36 changes: 36 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
43 changes: 43 additions & 0 deletions Components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from "react";
import { BiUser, BiFootball, BiTrophy } from "react-icons/bi";
import { MdOutlineExplore } from "react-icons/md";
import { GiTennisCourt } from "react-icons/gi";
import Link from "next/link";
import { useRouter } from "next/router";

const Footer = () => {
const { route: activeRoute } = useRouter();
const footerArray = [
{ route: "/matches", persianName: "مسابقات", icon: <GiTennisCourt /> },
{ route: "/explore", persianName: "اکتشاف", icon: <MdOutlineExplore /> },
{ route: "/footban", persianName: "فوتبان", icon: <BiFootball /> },
{ route: "/leagues", persianName: "لیگ‌ها", icon: <BiTrophy /> },
{ route: "/profile", persianName: "پروفایل", icon: <BiUser /> },
];

return (
<div className="py-4 right-0 h-8 border-t-2 border-gray-200">
<div className="flex justify-between items-center px-3">
{footerArray.map((item) => {
const { route, persianName, icon } = item;
return (
<Link href={route} key={route}>
<div
className={`flex gap-1 flex-col items-center cursor-pointer ${
route === activeRoute
? "text-green-600"
: "hover:text-green-500"
}`}
>
<div className="text-xl">{icon}</div>
<div>{persianName}</div>
</div>
</Link>
);
})}
</div>
</div>
);
};

export default Footer;
Empty file added Components/Footer/index.d.ts
Empty file.
1 change: 1 addition & 0 deletions Components/Footer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./Footer";
24 changes: 24 additions & 0 deletions Components/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { useEffect, useState } from "react";
import { TbAntennaBars5 } from "react-icons/tb";

const Header = () => {
const [date, setDate] = useState(new Date());

//update time every 30 seconds
useEffect(() => {
setInterval(() => setDate(new Date()), 30000);
}, []);

return (
<div className="border-b-2 py-3 px-4 text-lg text-gray-500 border-gray-200 h-8 flex items-center justify-between">
<div>
{date.getHours()}:{date.getMinutes()}
</div>
<div>
<TbAntennaBars5 />
</div>
</div>
);
};

export default Header;
Empty file added Components/Header/index.d.ts
Empty file.
1 change: 1 addition & 0 deletions Components/Header/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./Header";
16 changes: 16 additions & 0 deletions Components/Layout/Layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { FC } from "react";
import { LayoutProps } from "./index.d";
import Header from "../Header";
import Footer from "../Footer";

const Layout: FC<LayoutProps> = ({ children }) => {
return (
<div className="max-w-sm ">
<Header />
<main className="min-h-400 ">{children}</main>
<Footer />
</div>
);
};

export default Layout;
3 changes: 3 additions & 0 deletions Components/Layout/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export type LayoutProps = {
children: any;
};
1 change: 1 addition & 0 deletions Components/Layout/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./Layout";
50 changes: 50 additions & 0 deletions Components/MatchesScore/MatchesScore.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React, { FC } from "react";
import { MatchesScoreProps } from "./index.d";
import DateSelect from "./MatchesScoreComponents/DateSelect";
import ResultSearch from "./MatchesScoreComponents/ResultSearch";
import SingleLeagueContainer from "./MatchesScoreComponents/SingleLeagueContainer";

const MatchesScore: FC<MatchesScoreProps> = ({
fixtures,
leagues,
onSearchHandler,
searchField,
activeDateTabHandler,
}) => {
return (
<div>
<div>
<div className="text-xl font-bold text-right p-4">نتایج زنده</div>
<div className="mx-4 bg-gray-100">
<ResultSearch
searchValue={onSearchHandler}
searchField={searchField}
/>
</div>
<div>
<DateSelect activeDateTabHandler={activeDateTabHandler} />
</div>
</div>

<div className="h-96 overflow-y-scroll pb-4 bg-gray-200">
{fixtures.length < 1 && (
<div className="h-64 text-center w-full flex justify-center items-center">
SomeThing went wrong or your search result is empty
</div>
)}
{fixtures.length > 0 &&
leagues.map((league: string) => {
return (
<SingleLeagueContainer
leagueName={league}
key={league}
fixtures={fixtures}
/>
);
})}
</div>
</div>
);
};

export default MatchesScore;
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React, { FC, useEffect, useState } from "react";
import { DateSelectProps } from "./index.d";
import { getSpecificDate } from "../../../../utils/dateUtils";
import { AiFillCaretRight, AiFillCaretLeft } from "react-icons/ai";

const DateSelect: FC<DateSelectProps> = ({ activeDateTabHandler }) => {
const [dateArray, setDateArray] = useState([
{ date: getSpecificDate(-1), displayName: "دیروز" },
{ date: getSpecificDate(0), displayName: "امروز" },
{ date: getSpecificDate(1), displayName: "فردا" },
{ date: getSpecificDate(2), displayName: getSpecificDate(2) },
]);

const [activeDateTab, setActiveDateTab] = useState(dateArray[0].date);
const [shownIndex, setShownIndex] = useState(0);

useEffect(() => {
activeDateTabHandler(activeDateTab);
}, [activeDateTab]);

const rightScrollClickHandler = () => {
setShownIndex((prev) => prev - 1);
};
const leftScrollClickHandler = () => {
//check to see if date is already added to array by previous clicks
if (dateArray.some((e) => e.date === getSpecificDate(shownIndex + 3))) {
setShownIndex((prev) => prev + 1);
} else {
const newArray = [
...dateArray,
{
date: getSpecificDate(shownIndex + 3),
displayName: getSpecificDate(shownIndex + 3),
},
];

setDateArray(newArray);
setShownIndex((prev) => prev + 1);
}
};

return (
<div>
<ul className="h-12 flex gap-1 flex-row-reverse items-center justify-between px-1 ">
<li
className={shownIndex === 0 ? "invisible" : "cursor-pointer"}
onClick={rightScrollClickHandler}
>
<AiFillCaretRight />
</li>
{dateArray.slice(shownIndex, shownIndex + 4).map((item, index) => {
return (
<li
onClick={() => setActiveDateTab(item.date)}
className={`text-sm py-2 cursor-pointer ${
item.date === activeDateTab
? "border-b-4 border-green-500"
: "text-gray-400 hover:text-gray-500"
}
`}
key={index}
>
{item.displayName}
</li>
);
})}{" "}
<li onClick={leftScrollClickHandler} className="cursor-pointer">
<AiFillCaretLeft />
</li>
</ul>
</div>
);
};

export default DateSelect;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export type DateSelectProps = {
activeDateTabHandler: (activeDateTab: string) => string;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./DateSelect";
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React, { FC, useState } from "react";
import { ResultSearchProps } from "./index.d";
import { VscSearch } from "react-icons/vsc";

const ResultSearch: FC<ResultSearchProps> = ({ searchValue, searchField }) => {
return (
<div>
<div className="flex items-center h-12 flex-row-reverse">
<div className="mx-4 text-gray-500 ">
<VscSearch />
</div>
<input
placeholder="...جستجوی تیم یا لیگ"
className="h-full w-full bg-gray-100 text-right outline-none"
type="text"
id="search"
name="search"
value={searchField}
onChange={(e) => searchValue(e.target.value)}
/>
</div>
</div>
);
};

export default ResultSearch;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type ResultSearchProps = {
searchValue: any;
searchField: any;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./ResultSearch";
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React, { FC, useEffect, useState } from "react";
import { SingleLeagueProps } from "./index.d";
import { AiOutlineDown, AiOutlineUp } from "react-icons/ai";
import SingleMatchResult from "../SingleMatchResult";

const SingleLeagueContainer: FC<SingleLeagueProps> = ({
fixtures,
leagueName,
}) => {
const [leagueMatches, setLeagueMatches] = useState([]);
const [showResults, setShowResults] = useState(false);

//to not render filtered leagues
useEffect(() => {
const filteredLeague = fixtures.filter(
(item: any) => item.league.name === leagueName
);
setLeagueMatches(filteredLeague);
}, [fixtures]);

return (
<div className="mx-4 my-4 bg-white rounded-lg py-1 ">
<div className="flex flex-row-reverse justify-between items-center p-3 ">
<div className="flex flex-row-reverse gap-2 items-center ">
<div className="w-5 h-5">
{/* @ts-ignore */}
<img src={leagueMatches[0]?.league.logo} alt={leagueName} />
</div>
<div>{leagueName}</div>
</div>
<div
className="cursor-pointer hover:scale-125 hover:text-yellow-800"
onClick={() => setShowResults((prevState) => !prevState)}
>
{showResults ? <AiOutlineUp /> : <AiOutlineDown />}
</div>
</div>
{showResults && (
<div>
{leagueMatches.map((item: any) => {
const { teams, score, fixture } = item;
return (
<SingleMatchResult
score={score}
teams={teams}
fixture={fixture}
key={fixture.id}
/>
);
})}
</div>
)}
</div>
);
};

export default SingleLeagueContainer;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export type SingleLeagueProps = {
fixtures: any;
leagueName: string;
src?: string | undefined;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./SingleLeagueContainer";
Loading