OCARROT: Revolutionizing Competitive Programming with a Comprehensive Problem Archive
Official website Url-> Visit Ocarrot
Stacks
- Next.js
- Node.js
- Typescript
- MySQL
- Prismadb
Competitive programming has always been a vibrant arena for budding programmers and seasoned developers alike. With thousands of problems scattered across multiple websites, it's often a challenge to keep track of those intriguing challenges that leave a lasting impression. Enter OCARROT, a platform designed to address this very issue.
What is OCARROT?
OCARROT stands as a beacon for competitive programmers, offering a meticulously organized archive of programming problems. Not just any problems, but those that users find particularly compelling or challenging. It's a platform where users can record, share, and filter only the best problems, ensuring that no intriguing challenge ever goes forgotten.
Why OCARROT?
Every programmer has faced that moment when they recall a particularly challenging problem but can't remember where they encountered it. OCARROT's raison d'รชtre is to eliminate this struggle. By allowing users to log and categorize problems, the platform ensures that no problem ever goes missing in the vast ocean of algorithms.
1. Tailored Filtering
No longer do users need to rely on vague memory or cumbersome bookmarks. OCARROT offers robust filtering options:
- By Website: Whether it's LeetCode, Codeforces, or any other platform, users can filter problems based on their source.
- By Algorithm Tag: Perfect for those wanting to practice specific algorithms or data structures. From Graph Theory to Dynamic Programming, users can hone in on topics of interest.
- By Difficulty: Whether you're a newbie or a seasoned coder, find problems that match your skill level.
- By Comprehensive Level: Some problems are straightforward, while others require intricate understanding. Filter problems based on how in-depth they are.
2. Favorites at Your Fingertips
Found a problem that truly challenges you? Or perhaps one that offers a unique perspective? With a single click, users can add problems to their favorites, ensuring they're always just a click away.
3. Powerful Search
Sometimes, filtering isn't enough. Maybe you remember a specific term or a unique aspect of the problem. OCARROT's powerful search functionality lets users input keywords, offering relevant problems in an instant.
4. Full Control Over Your Posts
Posted a problem but realized you missed some details? Or perhaps you've found a more optimal solution? With OCARROT, users retain full control over their posts, allowing for edits and updates anytime. It ensures that the platform remains up-to-date and accurate, benefiting the entire community.
A Deep Dive into OCARROT's Structure
Let's explore the underlying architecture that powers OCARROT:
Database Tables and Relationships:
User
- Contains details of every registered user.
Account
- Manages user authentication.
- Related to
UserthroughuserId.
Session
- Manages user sessions.
- Related to
UserthroughuserId.
Problem
- Lists all programming problems.
- Related to
UserthroughuserId. - Related to
WebsitethroughwebsiteId. - Related to
DifficultythroughdifficultyId. - Related to
EnglishLevelthroughenglishLevelId.
ProblemsOnTags
- Maps problems to algorithm tags.
- Many-to-many relationship between
ProblemandTag.
Tag
- Allows for tagging problems.
Website
- Records the source of each problem.
Difficulty & EnglishLevel
- Categorize problems.
FavoriteIds
- Keeps track of a user's favorite problems.
- Related to
UserthroughuserId.
Hint
- Provides valuable hints for problems.
- Related to
ProblemthroughproblemId.
Core Technique
๐ Infinite Scroll for problem list
Click to expand!
Implementing Infinite Scroll in React
Introduction
Infinite scrolling is a design pattern in which content is loaded continuously as the user scrolls down the page, eliminating the need for pagination. In this article, we'll walk through the implementation of infinite scrolling in a React component using the react-intersection-observer package.
Infinite Scroll Component
The main component is InfiniteProblemCards, which is responsible for displaying problem cards and loading more when the user reaches the end of the list.
const InfiniteProblemCards: React.FC<InfiniteProblemCardsProps> = ({ searchParams, currentUser }) => {
const { problems, hasMore, setPage } = useFetchProblems({searchParams});
const { ref, inView } = useInView({ threshold: 0 });
useEffect(() => {
if (inView && hasMore) {
setPage(oldPage => oldPage + 1);
}
}, [inView, hasMore]);
// Render problem cards here...
return (
//...
);
};Here's a breakdown of the code:
useFetchProblems: A custom hook that fetches problems based on given search parameters.useInView: A hook fromreact-intersection-observerwhich gives us therefandinViewproperties. Therefis attached to a div at the bottom of our list, andinViewbecomestruewhen this div becomes visible on the screen.useEffect: This effect checks if the div is in view and there are more problems to fetch. If both conditions are true, it increments the page number to fetch the next set of problems.
Fetching Data for Infinite Scroll in React
Introduction
Fetching data efficiently is crucial for a smooth infinite scrolling experience. In this article, we'll discuss the implementation of the useFetchProblems hook and the getProblems function, which together fetch problems based on search parameters.
The useFetchProblems Hook
This custom hook manages the state of problems, the current page, and whether there are more problems to fetch.
const useFetchProblems = ({ searchParams }: UseFetchProblemsProps) => {
const [problems, setProblems] = useState<Problem[]>([]);
const [page, setPage] = useState(1);
const [hasMore, setHasMore] = useState(true);
useEffect(() => {
const fetchProblems = async (page: number) => {
// Fetch problems...
};
fetchProblems(page);
}, [page, searchParams]);
return { problems, hasMore, setPage };
};The main responsibilities of this hook are:
- Maintain the
problems,page, andhasMorestates. - Define a
fetchProblemsfunction inside auseEffectthat fetches problems based on the current page and search parameters.
The getProblems Function
This function constructs the appropriate API URL using the query-string library and fetches problems.
const getProblems = async (query: Query = {}): Promise<Problem[]> => {
const url = qs.stringifyUrl({
url: URL,
query: { /* ... */ },
});
const res = await fetch(url);
return res.json();
};The function takes a query object as an argument, which contains filtering parameters such as websiteId, tagId, etc. It then constructs a URL with these parameters and makes a GET request to fetch problems.
Conclusion
Infinite scrolling provides a seamless experience for users by continuously loading content as they scroll. By combining the react-intersection-observer library with efficient data fetching techniques, we can easily implement this feature in React applications.
๐ React Hook of action for favorite problem
Click to expand!
Article: Implementing a "Favorite" Feature in React
Introduction
One of the most common features in modern web applications is the ability for users to mark content as their "favorite". This interaction is often represented by a heart or star icon. In this article, we'll explore the implementation of a "favorite" feature for problems using Next.js, React, and Prisma.
The Hook: useFavorite
The core logic for the favorite functionality is encapsulated in a custom React hook called useFavorite. This hook manages the state and actions related to favoriting a problem.
Key Features of useFavorite:
State Management: The hook maintains the state for whether a problem is favorited (
hasFavorited) and if an API request is currently being made (isLoading).Toggle Logic: The
toggleFavoritefunction handles the logic for either adding or removing a problem from the user's favorites.User Authentication: If a user is not authenticated, they are prompted to log in when they attempt to favorite a problem.
const useFavorite = ({ problemId, currentUser }: IUseFavorite) => {
// ... state definitions ...
const toggleFavorite = useCallback(async (e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
if (!currentUser) {
return loginModal.onOpen();
}
setIsLoading(true);
try {
let request;
if (hasFavorited) {
request = () => axios.delete(`/api/favorites/${problemId}`);
} else {
request = () => axios.post(`/api/favorites/${problemId}`);
}
await request();
router.refresh();
toast.success('Like this problem!');
} catch (error) {
toast.error('Something went wrong.');
} finally {
setIsLoading(false);
}
},
[
currentUser,
hasFavorited,
problemId,
loginModal,
router
]);
return {
hasFavorited,
toggleFavorite,
isLoading,
}
}The Component: HeartButton
The HeartButton component is a visual representation of the "favorite" feature. Users can click on it to either add or remove a problem from their favorites.
const HeartButton: React.FC<HeartButtonProps> = ({
problemId,
currentUser
}) => {
const { hasFavorited, toggleFavorite, isLoading } = useFavorite({
problemId,
currentUser
});
// ... render logic ...
return (
<div
onClick={toggleFavorite}
className="..."
>
// ... icon display logic ..
{ isLoading ?
hasFavorited ? <div className="font-semibold">unsaving...</div> :
<div className="font-semibold">saving...</div> :
(
<>
<AiOutlineLike
size={32}
className="
fill-white
absolute
-top-[2px]
-right-[2px]
"
/>
<AiFillLike
size={28}
className={hasFavorited ? 'fill-rose-500' : 'fill-neutral-500/70'}
/>
</>
)
}
</div>
);
}API Endpoints: POST and DELETE
The favorite functionality relies on two key API endpoints:
- POST: Adds a problem to the user's favorites.
- DELETE: Removes a problem from the user's favorites.
These endpoints interact with a Prisma model named FavoriteIds that stores the relationships between users and their favorited problems.
model FavoriteIds{
id String @id @default(uuid())
favoriteId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
userId String
@@index([userId])
}The POST endpoint creates a new record in the FavoriteIds table linking the user to the problem they favorited. The DELETE endpoint removes this record, effectively "unfavoriting" the problem for the user.
Conclusion
Implementing a "favorite" feature in a web application enhances user engagement and provides a more personalized experience. By using Next.js for server-side logic, React for the frontend, and Prisma for database interactions, developers can create an efficient and user-friendly favorite feature. Whether it's articles, images, or problems, the strategy remains consistent: manage state, provide visual feedback, and handle data operations efficiently.
Conclusion
OCARROT isn't just another competitive programming platform. It's a tool that recognizes the value of every problem and ensures that memorable challenges remain within easy reach. By bridging the gaps between various competitive programming websites and offering a curated experience, OCARROT is set to change the way we approach and remember programming challenges.