JobFinder-Pro: A Flutter App Built with Appwrite

JobFinder-Pro: A Flutter App Built with Appwrite

Simplify Your Job Search with Appwrite-Powered Flutter App

ยท

5 min read

We are excited to introduce our submission for the Hashnode-Appwrite Hackathon - JobFinder-Pro. It's an innovative job finder application that connects recruiters and job seekers on a single platform, providing streamlined, efficient, and user-friendly job search and recruitment processes. We utilized Appwrite's robust features to build this application and are thrilled to share our project with the community.

Team Details

NameHashnodeTwitter
Desmond AdjohuAdjohu Desmond@27_wednesday
Gideon AcromondGideon Acromond@acromondx

Description of Project ๐ŸŽ‰

We chose to tackle this challenge due to the unique appeal of creating a dual-sided platform. We were intrigued by the idea of building an application that served two distinct yet interconnected user groups: recruiters and job applicants.

We recognized that each side has its own set of needs and challenges. Recruiters seek a reliable, efficient way to post job openings, review applications, and manage their hiring process. On the other hand, job seekers desire a user-friendly platform where they can easily search for opportunities, apply for jobs, and track their application status.

Features โœจ

Here are the distinct features provided in the views of both recruiters and applicants.

Recruiter Features

Post Jobs: Recruiters can post job openings by filling out a form that includes the job title, description, requirements, salary range, and location. This information is then available to job seekers.

Active and Closed Jobs: This feature allows recruiters to view and manage their posted jobs. They can see which jobs are currently active and open for applications, and which ones are closed because the positions have been filled.

View All Applicants: Recruiters can see a list of all job seekers who have applied for their posted jobs. This makes it easy to manage and review applications.

View Specific Applicant: Recruiters can view detailed information about a specific applicant, including their cv, cover letter, and contact information.

Accept and Reject Applications: After reviewing an application, recruiters can either accept or reject it. The job seeker is then notified of their application status.

Insights: This feature provides recruiters with data about their job postings, such as the number of applications, and accepted applications. This helps recruiters understand the performance of their postings.

Applicant Features

Search for Jobs: Job seekers can search for jobs using various criteria, such as job title or company name. This makes it easy to find jobs that match their preferences.

View Specific Job: Job seekers can view detailed information about a specific job, such as the job description, requirements, salary range, company information, and location.

Apply for Jobs: Once a job seeker finds a job they're interested in, they can apply directly through the app by submitting their resume and cover letter.

Saved Jobs: Job seekers can save jobs that they are interested in but are not ready to apply for yet. This way, they can easily find and apply for these jobs later.

View Status of Applied Jobs: This feature allows job seekers to track the status of their applications. They can see whether their applications have been accepted or rejected.

Tech Stack ๐Ÿ› ๏ธ

  • Flutter

  • Appwrite Cloud

    • Authentication

      We utilized Appwrite's straightforward and robust authentication system to manage both recruiter and applicant sign-ups in our app.

    • Appwrite Database

      We made extensive use of Appwrite's database services to store and manage a variety of data. This included information about both recruiters and applicants, as well as job-related data such as posted jobs and applied jobs.

    • Appwrite Storage

      To handle the storage of CVs and profile pictures, we integrated Appwrite's storage functionality into our app. This feature greatly simplified the process of managing and retrieving user-uploaded files.

Here's a simplified breakdown of how we used Appwrite in our app.

.
โ”œโ”€โ”€ Auth
โ”‚   โ”œโ”€โ”€ Sign up
โ”‚   โ”‚   โ”œโ”€โ”€ Recruiter
โ”‚   โ”‚   โ””โ”€โ”€ Applicant
โ”‚   โ””โ”€โ”€ Login
โ”œโ”€โ”€ Database
โ”‚   โ”œโ”€โ”€ Users
โ”‚   โ”‚   โ”œโ”€โ”€ Recruiter
โ”‚   โ”‚   โ””โ”€โ”€ Applicant
โ”‚   โ””โ”€โ”€ Job
โ”‚       โ”œโ”€โ”€ Posted Jobs
โ”‚       โ””โ”€โ”€ Applied Jobs
โ””โ”€โ”€ Storage
    โ”œโ”€โ”€ CV
    โ””โ”€โ”€ Profile Pictures

Challenges We Faced ๐Ÿš€

1. This project marked our first experience using Appwrite, necessitating us to delve into the Appwrite documentation and explore the features to understand how it could assist us with this app. We initially anticipated this to be quite challenging but found that the Appwrite documentation for Flutter was well-detailed and straightforward to implement.

2. Given that our app includes two distinct user types, our goal was to maintain a singular login system for everyone. This posed a significant challenge. However, we found a solution by utilizing the Account class and the create method within the Appwrite Flutter SDK. If the user signing up is a recruiter, we set the name in the create method to 'recruiter', and to 'applicant' for an applicant.

abstract class AuthInterface {
  FutureEither<model.User> recruiterSignUp({
    required String email,
    required String password,
  });
  FutureEither<model.User> applicantSignUp({
    required String email,
    required String password,
  });

// ...
}

class AuthAPI implements AuthInterface {
  final Account _account;
  AuthAPI({required Account account}) : _account = account;

  @override
  FutureEither<model.User> applicantSignUp({
    required String email,
    required String password,
  }) async {
    try {
      final signUp = await _account.create(
        userId: ID.unique(),
        email: email,
        password: password,
        name: 'applicant',
      );
      return right(signUp);
    } 
 // ...

  }

  @override
  FutureEither<model.User> recruiterSignUp({
    required String email,
    required String password,
  }) async {
    try {
      final signUp = await _account.create(
        userId: ID.unique(),
        email: email,
        password: password,
        name: 'recruiter',
      );
      return right(signUp);
    } 
     // ...
  }
}

This method gave us the ability to check the account name and navigate to the appropriate page upon login.

     home: ref.watch(currentUserAccountProvider).when(
            data: (user) {
              if (user != null) {
                 // ...
                return switch (user.name) {
                  'applicant' => const ApplicantPageNavigator(),
                  'recruiter' => const RecruiterPageNavigator(),
                  _ => const LoginView(),
                };
              }
                 return const SignupView();
            },
         // ...

Public Code Repo

Available on GitHub

Demo ๐ŸŽฌ