Projectify - Your teams,projects, & tasks. Together in one place.

Projectify - Your teams,projects, & tasks. Together in one place.

Projectify: Appwrite Hashnode Hackathon

Team Details

Description of Project

About The Project

Projectify is a simple, yet powerful web tool that gives you the luxury of collaborating, managing projects, and reaching new productivity peaks. The way your team works will always be unique and projectify keeps it that way.

The Problem it Seeks to Solve

Why keep that great idea to yourself when you can share it and form a solid community while working on it? Most platforms are usually one-sided in handling projects, they focus on just the organisational side and leave the communication side lacking. Projectify solves this by giving a team the ease to not just focus on the organisational side of their projects but also on the communication and collaboration side of it. Projectify makes managing and organising your team's project super easy and it comes with a lot of cool features like video conferencing, and real-time chatting.

Fun and efficient teamwork will always make the dream work.

All the conveniences in managing your projects can be found in Projectify. You can analyze the success of your activities and that of your teammates. Handling your projects is made super easy.

Projectify has the essentials to scale a global team. See your team grow in the sense of being able to manage tasks to match the target through collaboration.

Projectify comes with a chat system and video calling tool. You can set up online meetings and also keep your team together through chats. No need to travel and meet up all the time. Projectify handles communication needs for a global team.

Features and Screens

Landing Page

A simple landing page a visitor or user first sees when opting to use the app.

SignUp Screen

Login Screen

User Dashboard

Projects Page

Holds information to all projects a user is collaborating in.

Account Page

Workload Page

In-Project Page

Chat Screen

On project creation, a chatroom is created for the team.

Video Call Screen

PS: My coursemates volunteered to test the video call feature with me. They are Wonderful people.

Timer Screen

Be Productive! set timers so you can efficiently complete your tasks.

Development Process

Due to my exams, I had just three weeks to build out the entire project.

Project Planning and Execution
> May 23 - 24 : Project planning and choosing tech stack. 
> May 24 - June 06 : Build out and prepare the REST APIs 
> June 07 - 14 : Build out the Frontend
> June 15 : Wrote the article and submit the project few hours before the deadline.
Backend Initialisation
git init
npm install --save-dev nodemon
npm install node-appwrite express mongoose jsonwebtoken dotenv socket.io cors

How I used Appwrite service.

Authentication and Account creation.

I used the Appwrite "Account" to log in through the web and node-appwrite "Users" for sign-ups.

const login = async (email: string, password: string) => {
    setLoading(true)
    try {
      await account.createEmailSession(email, password)
      setLoading(false)
      setTimeout(() => navigate("/main/dashboard"), 700)
    } catch (error: any) {
      setLoading(false)
      throw Error(error.message)
    }
  }

Teams

Each project is created as a team and roles[owner, member] are given to members of the team.

export const createProject = async (req, res, next) => {
  try {
    const { title, project_cover, email, ...rest } = req.body
    // Create Team
    // Team - Project - ChatRoom will share the same $id.
    const team = await teams.create(ID.unique(), title)
    await teams.createMembership(
      team.$id,
      ["owner"],
      "http://localhost:8000",
      email
    )

    // Create Project
    let project
    if (project_cover) {
      project = await db.createDocument(
        process.env.DATABASE_ID,
        process.env.PROJECT_COLLECTION_ID,
        team.$id,
        { title, ...rest, project_cover }
      )
    } else {
      project = await db.createDocument(
        process.env.DATABASE_ID,
        process.env.PROJECT_COLLECTION_ID,
        team.$id,
        { title, ...rest }
      )
    }

    return res.status(200).json({
      success: true,
      data: { team, project },
      message: "Project Created successfully",
    })
  } catch (error) {
    return res.status(400).json({ success: false, message: error.message })
  }
}

Appwrite Databases

Was used to persist teams and user data.

export const getProjects = async (req, res, next) => {
  try {
    const { jwt } = req.query
    const client = new Client()
    client
      .setEndpoint("https://cloud.appwrite.io/v1")
      .setProject(process.env.PROJECT_ID)
      .setJWT(jwt)
    const db = new Databases(client)
    const team = new Teams(client)
    const teams = await team.list()
    if (teams.teams.length === 0)
      return res.status(200).json({ data: { projects: [] } })

    const teams_id = teams.teams.map((team) => team.$id)
    const projects = await db.listDocuments(
      process.env.DATABASE_ID,
      process.env.PROJECT_COLLECTION_ID,
      [Query.equal("$id", teams_id), Query.orderDesc("$createdAt")]
    )
    return res.status(200).json({
      success: true,
      data: { projects: projects.documents },
    })
  } catch (error) {
    return res.status(400).json({ success: false, message: error.message })
  }
}

Appwrite Storage

Was used to save user images and team files.

const onUploadImage = async () => {
    setLoading(true)
    try {
      const id = uuidv4()
      await storage.createFile(import.meta.env.VITE_BUCKET_ID, id, file as File)
      const img_url = storage.getFileView(import.meta.env.VITE_BUCKET_ID, id)
      await account.updatePrefs({ profile_picture: img_url })
      await refetch()
      setLoading(false)
      message.success("Profile Picture has been UPDATED")
    } catch (error: any) {
      setLoading(false)
      message.error(error.message)
    }
  }

Appwrite Realtime.

When a project manager gives a task, the task displays in the assigned-to member's dashboard in real-time.

Scheduled meetings also appear on team members' dashboards in real-time

useEffect(() => {
    client.subscribe(
      `databases.${import.meta.env.VITE_DATABASE_ID}.collections.${
        import.meta.env.VITE_PROJECT_COLLECTION_ID
      }.documents`,
      (response: any) => {
        refetchTasks()
          .unwrap()
          .then((data) => console.log(data))
      }
    )
  }, [])

Tech Stack

  • Appwrite Backend Service

  • Express/Node.js

  • Typescript

  • React.js

  • Redux toolkit query

  • Vite

  • Socket.io

  • Ant Design

  • Sass/Scss

  • Material Icons

Challenges I Faced

The hackathon started while I was still writing my last semester exams. I was a bit sad because I could only focus on the exam which will ultimately remove a week from my participation in the hackathon. After my exams, I quickly jumped right into the idea I had and started building from ground zero to what I have now.

Another challenge I had was in using the real-time feature from appwrite service. It was just one day left to the submission deadline and I was having issues using appwrite services. Thankfully their team solved the problem and I jumped right back in with more time on my hands to read the real-time documentation properly because one more day was added.

How I solved the real-time problem using useEffect hook from React.js

import { Client, Databases, Account, ID } from "appwrite"
const client = new Client()
client
  .setEndpoint("https://cloud.appwrite.io/v1")
  .setProject(import.meta.env.VITE_PROJECT_ID)
const db = new Databases(client)

useEffect(() => {
    client.subscribe(
      `databases.${import.meta.env.VITE_DATABASE_ID}.collections.${
        import.meta.env.VITE_PROJECT_COLLECTION_ID
      }.documents`,
      (response: any) => {
        refetchTasks()
          .unwrap()
          .then((data) => console.log(data))
      }
    )
  }, [])

Public Code Repo

Video demo link