Coder Social home page Coder Social logo

ascendynamics-nfp / ascendcoopplatform Goto Github PK

View Code? Open in Web Editor NEW
4.0 4.0 13.0 9.25 MB

An open-source collaboration platform for worker-owned cooperatives, nonprofits, and private organizations, built with Ionic and Firebase, to foster growth, real-time data-driven decision-making, and address basic human needs through community-based solutions.

Home Page: https://ascendynamics.org/

License: GNU Affero General Public License v3.0

TypeScript 64.97% JavaScript 0.36% HTML 25.53% SCSS 9.14%
nonprofits utopia worker-owned-cooperatives

ascendcoopplatform's Introduction

Ascend Co-op Platform

Ascend Co-op Platform is an open-source platform built using Ionic and Firebase, aimed at fostering collaboration and growth for worker-owned cooperatives, nonprofit organizations, and private organizations. It offers features like user profiles, group management, real-time data, and collaboration tools to address various challenges and facilitate communication between organizations.

Development

This project uses a continuous development process. As changes are made, they are immediately deployed to a development environment.

Latest Development Environment

You can view the latest version of the application in the development environment at the following link:

Latest Development Environment Version

We welcome QA contributions, bug reports, and discussions. Please feel free to create issues and discussions in this GitHub repository if you find any problems or have suggestions for improvements.

Connect With Us

Join our community and participate in discussions about the Ascend Co-op Platform. We have active communities on the following platforms:

We look forward to your contributions and engaging discussions!

Features

  • Worker-Owned Cooperative Incubator

    • Identify skill sets needed for worker-owned businesses
    • Connect skilled individuals with worker-owned businesses
    • Provide various services such as technical assistance and advice
  • Collaboration Platform

    • User and organization profiles
    • Group creation and management
    • Real-time data to address issues
    • Collaboration features, such as event proposals, voting, and commenting
  • Utopian Think Tank

    • Collaborate with organizations and research
    • Address basic human needs
    • Develop community-based solutions

Getting Started

Prerequisites

  • Node.js and npm
  • Ionic CLI
  • Firebase CLI (for deployment)
  1. Install Node.js, npm, Ionic CLI, and Angular CLI on your development machine.
  2. Clone this repository: git clone https://github.com/ASCENDynamics-NFP/AscendCoopPlatform.git
  3. Change to the project directory: cd AscendCoopPlatform
  4. Install dependencies: npm install
  5. Add your Firebase configuration to the src/environments/environment.ts and src/environments/environment.prod.ts files.
  6. Run the development server: ionic serve
  7. Open your browser and navigate to http://localhost:8100/ to view the app.

We welcome contributions from the community. To get started, please follow these steps:

  1. Fork the repository.
  2. Create a new branch for your feature or bugfix: git checkout -b my-feature-branch
  3. Make your changes and commit them with a descriptive commit message.
  4. Push your branch to your fork: git push origin my-feature-branch
  5. Open a pull request against the main repository.

Please follow the project's coding conventions and ensure that your changes don't break any existing functionality or introduce new bugs. For more information on the contribution process, please see our CONTRIBUTING.md file.

License This project is licensed under the AGPL License. For more details, see the LICENSE file.

Support If you have any questions or need help with the project, please open an issue on the GitHub repository or reach out to the project maintainers.

ascendcoopplatform's People

Contributors

aartichoudhary avatar hassantanveer avatar inventorxtreme avatar jeizmn avatar joaopedro04 avatar mufniarz avatar nikko-adrian-pacleb avatar nyero2023 avatar sabarno-15102002 avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

ascendcoopplatform's Issues

Updated README to share a link to the Dev Environment

Description

Add the sections below to the README.md file under the title and description.

Motivation

I'm hoping that having these sections will encourage others to contribute in making issues and adding to discussions.

Proposed Solution (Optional)

## Development
This project uses a continuous development process. As changes are made, they are immediately deployed to a development environment.

## Latest Development Environment
You can view the latest version of the application in the development environment at the following link: 

[Latest Development Environment Version](https://ascendcoopplatform-dev.web.app/)

We welcome QA contributions, bug reports, and discussions. Please feel free to create issues and discussions in this GitHub repository if you find any problems or have suggestions for improvements.

## Connect With Us
Join our community and participate in discussions about the Ascend Coop Platform. We have active communities on the following platforms:

- [Facebook Group](https://www.facebook.com/groups/ascendynamics)
- [LinkedIn Page](https://www.linkedin.com/company/ascendynamics-nfp)
- [Join our Slack workspace](https://join.slack.com/t/ascendynamicsnfp/shared_invite/zt-1vkqh53sw-BchYV8NmOhOOkRIp8~L~xw)

We look forward to your contributions and engaging discussions!

15: Implement Group Avatar Upload

#7 #10 #74

Description:

In order to allow better personalization and identification, we should provide group administrators with the ability to upload an avatar image for their group. The uploaded image should be securely stored in Firebase and prominently displayed on the group's profile.

Tasks:

  1. Update Group Profile Schema

    • The Group profile schema needs to be updated to include a new field for the avatar image.
  2. UI Changes

    • The Group Profile edit page must be modified to include an 'Upload Avatar' button.
  3. Implement Image Upload

    • Back-end logic is needed to securely upload the image to Firebase Storage. After a successful upload, the URL of the image should be stored in the group's profile in Firestore.
  4. Display Avatar in Group Profile

    • Update the group profile UI to display the group's avatar if one is provided.
  5. Error Handling

    • Implement error handling to catch and report upload failures in a user-friendly way.
  6. Testing

    • The image upload functionality must be tested with various file sizes and formats to ensure it works as expected.
  7. Documentation

    • Document the implementation details and any limitations of the avatar upload functionality.

Acceptance Criteria:

  1. Group administrators are able to upload an avatar image from the group profile edit page.
  2. The uploaded images are correctly stored in Firebase Storage, and the URL is stored in the group's Firestore profile.
  3. The group avatars are correctly displayed on their profiles.
  4. Error handling works as expected and any upload failures are correctly reported to the user.
  5. The feature works as expected for various file sizes and formats.
  6. The implementation details and limitations are clearly documented.

9. Integrate Firebase Authentication Service with UI

Step 1: Import the AuthService

In each of the authentication components (signup.component.ts, login.component.ts, logout.component.ts), import the AuthService:

import { AuthService } from '../services/auth.service';

Step 2: Inject the AuthService

In the constructor of each component, inject the AuthService:

constructor(private authService: AuthService) { }

Step 3: Bind Form Inputs to Service Functions

In the onSubmit() function of the signup.component.ts and login.component.ts files, call the respective AuthService function:

For signup:

onSubmit(form) {
  const { email, password } = form.value;
  this.authService.signUp(email, password).then(() => {
    // handle successful sign up
  }).catch((error) => {
    // handle error
  });
}

For login:

onSubmit(form) {
  const { email, password } = form.value;
  this.authService.signIn(email, password).then(() => {
    // handle successful login
  }).catch((error) => {
    // handle error
  });
}

Step 4: Handle Form Submission

In the logout.component.ts file, call the signOut() function when the logout button is clicked:

logout() {
  this.authService.signOut().then(() => {
    // handle successful logout
  }).catch((error) => {
    // handle error
  });
}

Step 5: Display Error or Success Messages

To display error or success messages, you can use Ionic's ToastController. First, import and inject it in each component:

import { ToastController } from '@ionic/angular';

constructor(private authService: AuthService, private toastController: ToastController) { }

Then, create a function to present a toast:

async presentToast(message: string) {
  const toast = await this.toastController.create({
    message: message,
    duration: 2000
  });
  toast.present();
}

You can then use this function to display a message when an operation is successful or fails:

this.authService.signUp(email, password).then(() => {
  this.presentToast('Signed up successfully');
}).catch((error) => {
  this.presentToast('Error signing up: ' + error.message);
});

Repeat this for the login and logout operations.

Now, your authentication UI should be fully integrated with the Firebase Authentication Service. Users should be able to sign up, log in, and log out, and they should see appropriate messages when these operations succeed or fail.

Bug: Login Bug with Google Authentication

Description

Users who register via Google Authentication encounter a problem when attempting to log in using their email and password. An error is thrown in the background and the user is not notified about the problem, leaving them confused and unable to access the application.

Steps to Reproduce

  1. Go to the login page.
  2. Register a new account using Google Authentication.
  3. Log out of the newly created account.
  4. Attempt to log in again, this time using the email and password associated with the Google account.
  5. Notice that the login fails, but no error message is shown.

Expected Behavior

When a user who registered via Google Authentication tries to log in with their email and password, they should either be able to log in successfully or receive a clear error message informing them about the proper login method.

Actual Behavior

An error is thrown in the background and the user is not notified about the problem. The user is left on the login screen without any indication of what went wrong.

Screenshots (Optional)

image

Environment (Optional)

  • OS: All
  • Browser: All
  • Version: Current version

Additional Context (Optional)

This bug may confuse and frustrate new users, affecting user retention and overall user experience. It's important to either allow these users to log in using their email and password, or to provide a clear message explaining that they need to log in using Google Authentication.

11: Implement User-to-Group Interaction

#7 #10
Step 1: Update the Data Structure in Firebase

First, you'll need to update your data structure in Firebase to accommodate user-group interactions. You might create a collection of join requests and a member list for each group.

For example, a group document could be structured as follows:

{
  "groupName": "Group1",
  "members": ["user1", "user2"],
  "joinRequests": ["user3"]
}

Step 2: Update the Group Service

Next, update the group service to handle user-group interactions. This might include methods for sending join requests, accepting join requests, leaving groups, and retrieving group information.

Here's an example of how you might implement these methods:

// GroupService

sendJoinRequest(groupId, userId) {
  // Add user to the group's joinRequests array
  return this.db.object(`/groups/${groupId}/joinRequests/${userId}`).set(true);
}

acceptJoinRequest(groupId, userId) {
  // Remove user from the group's joinRequests array
  this.db.object(`/groups/${groupId}/joinRequests/${userId}`).remove();

  // Add user to the group's members array
  return this.db.object(`/groups/${groupId}/members/${userId}`).set(true);
}

leaveGroup(groupId, userId) {
  // Remove user from the group's members array
  return this.db.object(`/groups/${groupId}/members/${userId}`).remove();
}

getGroupInfo(groupId) {
  // Retrieve the group's information
  return this.db.object(`/groups/${groupId}`).valueChanges();
}

Step 3: Update the Group Component

Update the group component to allow users to interact with groups. This might involve adding buttons for sending join requests, accepting join requests, and leaving groups, and displaying group information.

Here's an example of how you might implement these features:

<!-- GroupComponent -->

<h2>{{ group.groupName }}</h2>

<div *ngIf="group.joinRequests.includes(currentUserId)">
  <button (click)="acceptJoinRequest()">Accept Join Request</button>
</div>

<div *ngIf="group.members.includes(currentUserId)">
  <button (click)="leaveGroup()">Leave Group</button>
</div>

<div *ngIf="!group.members.includes(currentUserId) && !group.joinRequests.includes(currentUserId)">
  <button (click)="sendJoinRequest()">Join Group</button>
</div>
// GroupComponent

group: any;
currentUserId = 'user1';  // Replace with the current user's ID

constructor(private groupService: GroupService) {}

ngOnInit() {
  this.groupService.getGroupInfo('Group1').subscribe(group => this.group = group);
}

sendJoinRequest() {
  this.groupService.sendJoinRequest('Group1', this.currentUserId);
}

acceptJoinRequest() {
  this.groupService.acceptJoinRequest('Group1', this.currentUserId);
}

leaveGroup() {
  this.groupService.leaveGroup('Group1', this.currentUserId);
}

Step 4: Test Your User-Group Interaction Feature

After implementing the above steps, you should be able to interact with groups. Test each functionality to ensure it works as expected.

image image

1. Setup Firebase Project and Enable Authentication Method

  1. Create a Firebase project:

  2. Enable the authentication method:

    • In the Firebase console, click on the newly created project.
    • From the project overview page, click on "Authentication" in the left-hand sidebar.
    • Click on the "Sign-in method" tab.
    • Here, you'll see a list of sign-in providers. Click on the provider you wish to enable (for example, Email/Password, Google, Facebook, etc.) and follow the instructions to enable it.
  3. Get your Firebase configuration object:

    • From the project overview page, click on the gear icon next to "Project Overview" and select "Project settings."
    • Here, you'll find your Firebase SDK snippet under "Your apps" section.
    • Choose the "Config" option to see your Firebase configuration object. It will look something like this:
var firebaseConfig = {
  apiKey: "AIzaSy...",
  authDomain: "your-project-id.firebaseapp.com",
  databaseURL: "https://your-project-id.firebaseio.com",
  projectId: "your-project-id",
  storageBucket: "your-project-id.appspot.com",
  messagingSenderId: "your-sender-id",
  appId: "your-app-id",
  measurementId: "G-measurement-id",
};
  1. Secure your Firebase project:
    • Make sure to add your application's domain to the list of authorized domains in Firebase Console -> Authentication -> Sign-in method -> Authorized domains.
    • Also, consider setting up security rules for your database and storage if applicable.

Remember, the Firebase configuration object contains sensitive information. Be sure to secure it properly, avoid committing it directly into your public repository. Consider using environment variables or some form of secret management.

After these steps, you should have a Firebase project set up with your desired authentication method enabled.

#2 Issue
#9 Discussion

Add Custom Error Handler for All Firebase Authentication Errors

Description:

We need to improve the user experience by implementing a custom error handler for all Firebase authentication errors. This handler should catch and interpret Firebase errors and display user-friendly error messages instead. This includes, but is not limited to, errors like "auth/email-already-in-use", "auth/invalid-email", "auth/operation-not-allowed", and "auth/weak-password".

Tasks:

  1. Task 1: Research Firebase Authentication Errors

    • Understand the possible Firebase authentication errors. Firebase documentation will be useful for this task.
  2. Task 2: Design Error Messages

    • Based on the Firebase authentication errors, design user-friendly error messages that will be displayed to the user.
  3. Task 3: Implement Error Handler

    • Implement a centralized error handler for Firebase authentication errors.
    • This handler should catch Firebase errors, and map them to the designed error messages.
    • If an error is not recognized, the handler should fall back to a generic error message.
  4. Task 4: Integrate Error Handler

    • Replace existing Firebase error handling code with calls to the new error handler.
    • This should be done wherever we're making calls to Firebase for authentication.
  5. Task 5: Test Error Handler

    • Test the error handler with various scenarios to make sure all Firebase authentication errors are caught and handled properly.

Acceptance Criteria:

  • A custom error handler for Firebase authentication errors is implemented.
  • The handler catches Firebase errors and shows user-friendly messages.
  • The handler has been integrated into the existing codebase and is used wherever Firebase authentication is used.
  • All Firebase authentication errors are correctly caught and handled by the new error handler.
  • The error handler has been thoroughly tested to ensure it works as expected.

Additional Context:

This improvement is part of an ongoing effort to improve the user experience of our application. Please follow our coding and style guidelines when implementing this feature.
#83 #81


The following is a complete example of how you would handle Firebase authentication errors by using a toast message with a title.

First, import the necessary dependencies in your service file:

import { ToastController } from '@ionic/angular';
import { Injectable } from '@angular/core';

Then, inject ToastController in your service's constructor:

@Injectable({ providedIn: 'root' })
export class FirebaseAuthService {
  constructor(private toastController: ToastController) { }

Create a helper function to show the toast:

  private async showToast(message: string, title: string): Promise<void> {
    const toast = await this.toastController.create({
      message: `${title}: ${message}`,
      duration: 2000
    });
    await toast.present();
  }

Next, define a mapping of error codes to user-friendly titles and messages:

  private readonly FIREBASE_AUTH_ERROR_CODE_TITLES = {
    'auth/email-already-in-use': 'Email already in use',
    'auth/invalid-email': 'Invalid email',
    // add more error code titles as needed...
  }

  private readonly FIREBASE_AUTH_ERROR_CODE_MESSAGES = {
    'auth/email-already-in-use': 'The email address is already in use by another account.',
    'auth/invalid-email': 'The email address you have entered is not valid.',
    // add more error code messages as needed...
  }

Then, create the error handling method:

  handleFirebaseAuthError(error: { code: string, message: string }) {
    const errorTitle = this.FIREBASE_AUTH_ERROR_CODE_TITLES[error.code] || 'Error';
    const errorMessage = this.FIREBASE_AUTH_ERROR_CODE_MESSAGES[error.code] || error.message;

    this.showToast(errorMessage, errorTitle); // Show the toast with the error message

    return errorMessage;
  }

This way, whenever a Firebase Authentication error occurs, it will be handled by FirebaseAuthErrorHandler.handleFirebaseAuthError(), and a user-friendly error message will be shown in a toast. Remember to call handleFirebaseAuthError within a try-catch block during authentication.

8: Implement User Search Functionality

#7 #10

  1. Install AngularFire and Firebase

    If not done already, you will need to install Firebase and AngularFire in your project. AngularFire is the official Angular library for Firebase, and it will make working with Firebase in Angular much easier.

    You can install both with npm:

    npm install firebase @angular/fire

    Make sure to setup Firebase in your project and initialize it with your Firebase project credentials.

  2. Create a User Service

    Create a service that will handle all user-related operations, including the search.

    ng generate service services/user

    This will create a user.service.ts file in your services directory.

  3. Implement the Search Method

    In user.service.ts, import AngularFireDatabase and inject it in the constructor.

    import { AngularFireDatabase } from '@angular/fire/database';
    
    constructor(private db: AngularFireDatabase) {}

    Then, add a method to perform the search:

    searchUsers(start, end): Observable<any[]> {
      return this.db.list('/users', ref =>
        ref.orderByChild('username').startAt(start).endAt(end)
      ).valueChanges();
    }

    This will return an Observable of users whose usernames are between the start and end parameters.

  4. Create the Search UI

    In your search component, add an input field for the search term and a button to perform the search.

    <input [(ngModel)]="searchTerm" placeholder="Search users">
    <button (click)="search()">Search</button>

    Implement the search method in your component's TypeScript file:

    searchTerm = '';
    
    constructor(private userService: UserService) {}
    
    search() {
      this.userService.searchUsers(this.searchTerm, this.searchTerm + '\uf8ff')
        .subscribe(users => {
          // Do something with the users
        });
    }

    Note that '\uf8ff' is a very high Unicode character which will match all strings that start with the search term.

  5. Test Your Search

    After implementing the above steps, you should be able to search users by their username. Input a username in the search field and click the Search button. You should see a list of users that match the search term.

image

Configure Trello Board

#32

Description

Configure Trello Board so that Project Managers can manage the workflow.

Motivation

This should help to Project Managers to prioritize tasks and view that status of current issues in GitHub.

Proposed Solution (Optional)

Integrate GitHub with Trello.

Additional Context (Optional)

Will need assistance from project manager.

2: Implement User Profile Model in Firebase

#7 #10

  1. Create User Model:

    Start by defining a TypeScript interface for the User Profile in your Ionic project. It should match the structure of the User documents in your Firestore database. Here's a simple example:

    export interface User {
        id: string;
        name: string;
        email: string;
        profilePicture: string;
        bio: string;
    }
  2. Create Firestore Service:

    You'll then need to create a service that interacts with Firestore to perform CRUD operations on the User documents. You can generate a new service in your Ionic project using the Angular CLI:

    ng generate service services/firestore

    Then, in the firestore.service.ts file, import the necessary Firebase and AngularFire modules:

    import { AngularFirestore } from '@angular/fire/compat/firestore';
    import { Injectable } from '@angular/core';

    Inject AngularFirestore in the constructor of the service:

    constructor(private firestore: AngularFirestore) { }
  3. Implement CRUD operations:

    Now, you can implement the necessary CRUD operations for the User Profile. Here's an example of a getUserProfile method, which retrieves a User Profile document from Firestore:

    getUserProfile(userId: string) {
        return this.firestore.collection('users').doc<User>(userId).valueChanges();
    }

    You'll want to implement similar methods for creating, updating, and deleting User Profiles.

  4. Using the Firestore Service:

    Finally, you can use this Firestore service in your Ionic components to interact with the User Profile documents in your Firestore database.

Remember to handle any errors and edge cases that might occur, such as what happens if a document doesn't exist or if a network error occurs.

Implement User Registration and Login with Firebase Authentication

Description

Problem: Our platform currently lacks a user registration and login system. This is a crucial feature for user management and access control. We need a secure and reliable way for users to create an account or sign into their existing one.

Motivation

  1. User Accessibility: Providing multiple sign-in methods will enhance user accessibility and convenience.
  2. Security: Firebase's built-in security measures will ensure the protection of user data and maintain the security of our platform.
  3. Streamlined Development: Using Firebase Authentication will simplify our development process, allowing us to allocate more time to other aspects of the project.

Proposed Solution (Optional)

I propose we leverage Firebase's Authentication features to handle user registration and login. Firebase Authentication provides a comprehensive suite of authentication options, including email and password, phone numbers, and federated identity providers like Google, Facebook, and Twitter.

Additional Context (Optional)

Tasks:

  1. Create user registration and login pages.
  2. Integrate Firebase Authentication for handling user registration and login.
  3. Test the registration and login process with different sign-in methods.
  4. Review and address any security concerns.

Acceptance Criteria:

  1. Users can successfully register an account with various sign-in methods.
  2. Users can successfully log in to their account with the correct credentials.
  3. Users cannot log in with incorrect credentials.
  4. User data is securely managed and protected.

https://market.ionicframework.com/
Use a template that's compatible with Ionic 7.

I'd appreciate it if we could discuss this further to finalize our implementation plan. Any feedback, suggestions, or concerns are welcome.

Best regards,
@mufniarz

5: Create Group Profile UI

#7 #10

  1. Create a new page:

    Use the Ionic CLI to generate a new page for the Group Profile:

    ionic generate page GroupProfile

    This will create a new folder under src/app/group-profile with four files: group-profile.page.html (the template), group-profile.page.scss (the styles), group-profile.page.ts (the class), and group-profile.page.spec.ts (the test).

  2. Design the template:

    Open group-profile.page.html and start designing your Group Profile page. You might want to display the group's name, description, and any other relevant information.

    Here's a simple example:

    <ion-header>
      <ion-toolbar>
        <ion-title>Group Profile</ion-title>
      </ion-toolbar>
    </ion-header>
    
    <ion-content>
      <ion-card>
        <ion-card-header>
          <ion-card-title>{{ group.name }}</ion-card-title>
        </ion-card-header>
        <ion-card-content>
          <p>Description: {{ group.description }}</p>
          <!-- Include other group details here -->
        </ion-card-content>
      </ion-card>
    </ion-content>
  3. Update the class:

    In group-profile.page.ts, you'll need to fetch the group's data from Firestore and assign it to a property in your class. This property can then be used in your template to display the group's data.

    Here's an example:

    import { Component, OnInit } from '@angular/core';
    import { FirestoreService } from '../services/firestore.service';
    
    @Component({
      selector: 'app-group-profile',
      templateUrl: './group-profile.page.html',
      styleUrls: ['./group-profile.page.scss'],
    })
    export class GroupProfilePage implements OnInit {
      group: any;
    
      constructor(private firestoreService: FirestoreService) { }
    
      ngOnInit() {
        this.firestoreService.getGroupProfile('groupId').subscribe(group => {
          this.group = group;
        });
      }
    }

    Note that 'groupId' should be replaced with the actual ID of the group whose profile you want to display. How you get this ID will depend on your application's routing and authentication setup.

  4. Style the page:

    You can use the SCSS file group-profile.page.scss to add styles to your Group Profile page. The Ionic framework provides a variety of CSS utilities and pre-built components that you can use to design your page.

  5. Test the page:

    Finally, make sure to test your page both in a web browser and on a mobile device to ensure it looks and behaves as expected. Remember to handle any edge cases, such as what should be displayed if the group's data fails to load.

  6. Route to the Group Profile Page:

    In your app-routing.module.ts, add a route to your group profile page.

    const routes: Routes = [
      // other routes
      {
        path: 'group-profile',
        loadChildren: () => import('./group-profile/group-profile.module').then(m => m.GroupProfilePageModule)
      }
    ];

    Now, you can navigate to this page from any other page by using the Angular router:

    this.router.navigate(['/group-profile']);

4. Implement Signup Functionality

  1. Create a Signup Form:

    • In your signup component (let's call it signup.component.ts), create a signup form using Angular's FormGroup and FormControl.

    • Import the necessary dependencies:

      import { FormBuilder, Validators } from '@angular/forms';
    • In your component's constructor, initialize your form:

      constructor(private fb: FormBuilder) { }
      
      signupForm = this.fb.group({
        email: ['', [Validators.required, Validators.email]],
        password: ['', [Validators.required, Validators.minLength(6)]],
      });
    • This creates a form with two fields, email and password, with appropriate validators.

  2. Inject AuthService:

    • Import and inject the AuthService that you created in the previous issue.

      import { AuthService } from '../services/auth.service';
      
      constructor(private fb: FormBuilder, private authService: AuthService) { }
  3. Implement Signup Method:

    • Create a signup method in your component that calls the signUp method from AuthService:

      async signup() {
        const { email, password } = this.signupForm.value;
        try {
          const user = await this.authService.signUp(email, password);
          console.log(user);
        } catch (error) {
          console.log(error);
        }
      }
  4. Update Signup Template:

    • In your signup component's template (let's call it signup.component.html), bind the form controls to input fields:

      <form [formGroup]="signupForm" (ngSubmit)="signup()">
        <label>
          Email:
          <input type="email" formControlName="email">
        </label>
        <label>
          Password:
          <input type="password" formControlName="password">
        </label>
        <button type="submit">Sign Up</button>
      </form>
    • This binds your email and password form controls to the corresponding input fields, and binds the form's submit event to your signup method.

  5. Test Signup Functionality:

    • Now you can test your signup functionality. Run your Ionic app, navigate to your signup page, enter an email and password, and click the Sign Up button. If everything is set up correctly, the user should be created in Firebase, and the user information should be logged to the console.

Please, be sure to handle errors and edge cases appropriately in your actual application. The above implementation is a basic example and may not cover all scenarios.

#2
#9

4: Create User Profile UI

#7 #10

  1. Create a new page:

    Use the Ionic CLI to generate a new page for the User Profile:

    ionic generate page UserProfile

    This will create a new folder under src/app/user-profile with four files: user-profile.page.html (the template), user-profile.page.scss (the styles), user-profile.page.ts (the class), and user-profile.page.spec.ts (the test).

  2. Design the template:

    Open user-profile.page.html and start designing your User Profile page. You might want to display the user's name, email, and any other relevant information.

    Here's a simple example:

    <ion-header>
      <ion-toolbar>
        <ion-title>User Profile</ion-title>
      </ion-toolbar>
    </ion-header>
    
    <ion-content>
      <ion-card>
        <ion-card-header>
          <ion-card-title>{{ user.name }}</ion-card-title>
        </ion-card-header>
        <ion-card-content>
          <p>Email: {{ user.email }}</p>
          <!-- Include other user details here -->
        </ion-card-content>
      </ion-card>
    </ion-content>
  3. Update the class:

    In user-profile.page.ts, you'll need to fetch the user's data from Firestore and assign it to a property in your class. This property can then be used in your template to display the user's data.

    Here's an example:

    import { Component, OnInit } from '@angular/core';
    import { FirestoreService } from '../services/firestore.service';
    
    @Component({
      selector: 'app-user-profile',
      templateUrl: './user-profile.page.html',
      styleUrls: ['./user-profile.page.scss'],
    })
    export class UserProfilePage implements OnInit {
      user: any;
    
      constructor(private firestoreService: FirestoreService) { }
    
      ngOnInit() {
        this.firestoreService.getUserProfile('userId').subscribe(user => {
          this.user = user;
        });
      }
    }

    Note that 'userId' should be replaced with the actual ID of the user whose profile you want to display. How you get this ID will depend on your application's routing and authentication setup.

  4. Style the page:

    You can use the SCSS file user-profile.page.scss to add styles to your User Profile page. The Ionic framework provides a variety of CSS utilities and pre-built components that you can use to design your page.

  5. Test the page:

    Finally, make sure to test your page both in a web browser and on a mobile device to ensure it looks and behaves as expected. Remember to handle any edge cases, such as what should be displayed if the user's data fails to load.

  6. Route to the User Profile Page:

    In your app-routing.module.ts, add a route to your user profile page.

    const routes: Routes = [
      // other routes
      {
        path: 'user-profile',
        loadChildren: () => import('./user-profile/user-profile.module').then(m => m.UserProfilePageModule)
      }
    ];

    Now, you can navigate to this page from any other page by using the Angular router:

    this.router.navigate(['/user-profile']);

Firebase Authentication Error: auth/email-already-in-use

Description

In our application, when attempting to sign up with an email that is already registered, Firebase throws an error (auth/email-already-in-use). Our current error handling mechanism simply logs the error and rethrows it, resulting in an uncaught promise rejection.

Steps to Reproduce

  1. Start the application and navigate to the sign-up page.
  2. Enter an email address that is already registered in the system.
  3. Enter a password.
  4. Click on the "Sign Up" button.
  5. See the error logged in the console.

Expected Behavior

When a user attempts to sign up with an email address that is already registered, the application should handle this error gracefully by displaying a user-friendly error message, and not throw an unhandled promise rejection error.

Actual Behavior

Currently, when a user tries to sign up with an email that is already in use, the error is logged in the console and re-thrown, causing an unhandled promise rejection.

Screenshots (Optional)

If applicable, add screenshots to help explain your problem.

Environment (Optional)

  • OS: macOS
  • Browser (if applicable): Chrome
  • Version (if applicable): 96.0.4664.55

Additional Context (Optional)

This issue can lead to a poor user experience as they are not informed of the actual issue when they attempt to sign up with an email that is already in use. It would be beneficial to catch this specific error, and provide a meaningful response to the user, perhaps prompting them to log in instead or use a different email address.

Add CI/CD Workflow

Description

Configure the CI/CD process in order to deploy merged apps into the development environment.

Motivation

Configuring the CI/CD process will allow the maintainers of the repository and code to focus on writing out new features and managing the project by reducing deployment steps. It will also allow the community to view new features as they're merged in.

Proposed Solution (Optional)

Create two GitHub workflows.

  1. Pull Request - the project would build and run all tests before it could be merged.
  2. Merge - the project would be deployed into the dev environment.

Additional Context (Optional)

6. Implement Logout Functionality

  1. Update AuthService:

    • In your AuthService (let's call it auth.service.ts), add a signOut method that calls Firebase's signOut method:

      import { AngularFireAuth } from '@angular/fire/auth';
      
      constructor(private afAuth: AngularFireAuth) { }
      
      async signOut() {
        try {
          await this.afAuth.signOut();
        } catch (error) {
          console.log(error);
        }
      }
    • This method attempts to sign out the currently logged in user.

  2. Inject AuthService:

    • In the component where you want to implement the logout functionality (for example, in a navigation bar component), import and inject the AuthService.

      import { AuthService } from '../services/auth.service';
      
      constructor(private authService: AuthService) { }
  3. Implement Logout Method:

    • Create a logout method in your component that calls the signOut method from AuthService:

      async logout() {
        try {
          await this.authService.signOut();
        } catch (error) {
          console.log(error);
        }
      }
  4. Add Logout Button:

    • In your component's template, add a button that calls the logout method when clicked:

      <button (click)="logout()">Log Out</button>
  5. Test Logout Functionality:

    • Now you can test your logout functionality. Run your Ionic app, log in with a user, then click the Log Out button. If everything is set up correctly, the user should be logged out.

Remember to handle errors and edge cases appropriately in your actual application. The above implementation is a basic example and may not cover all scenarios.

#2
#9

14: Implement User Avatar Upload

Description:

Our platform needs to provide the ability for users to upload an avatar image for their profiles. The image needs to be securely stored in Firebase and should be displayed on the user's profile.

Tasks:

  1. Update User Profile Schema

    • Update the User profile schema in Firebase to include a new field for the avatar image.
  2. UI Changes

    • Modify the User Profile edit page to include an 'Upload Avatar' button.
  3. Implement Image Upload

    • Implement the backend logic to securely upload the image to Firebase Storage, and store the URL of the uploaded image in the user's profile in Firestore.
  4. Display Avatar in User Profile

    • Update the user profile UI to display the user's avatar if one exists.
  5. Error Handling

    • Implement appropriate error handling for image upload failures.
  6. Testing

    • Test the image upload functionality with various file sizes and formats to ensure it works as expected.
  7. Documentation

    • Document the implementation details and any limitations of the avatar upload functionality.

Acceptance Criteria:

  1. Users can upload an avatar image from their profile edit page.
  2. Uploaded images are correctly stored in Firebase Storage and the URL is stored in the user's Firestore profile.
  3. Users' avatars are correctly displayed on their profiles.
  4. Error handling correctly catches and reports upload failures.
  5. The feature works as expected for various file sizes and formats.
  6. Implementation details and limitations are clearly documented.

16: Create User Profile Edit Page

#7 #10

Description:

We need to provide our users with the ability to edit their own profile information. This task involves designing and implementing a User Profile Edit page. This page should be easily accessible, preferably directly linked from the user's profile page.

Tasks:

  1. UI Design

    • Design the layout of the User Profile Edit page. The design should be intuitive and user-friendly, making it easy for users to locate and edit fields.
  2. Implement Edit Page

    • Implement the design in the front-end code. This will be a new page that includes form fields for all editable attributes of the user profile.
  3. Field Validation

    • Implement client-side validation to ensure the data entered by the user is valid before it is submitted.
  4. Link to Profile

    • Add a link or button on the user's profile page that leads to the Edit page.
  5. Testing

    • Test the page with various user inputs and ensure it handles invalid input gracefully.

Acceptance Criteria:

  1. The User Profile Edit page has been implemented according to the provided design.
  2. The Edit page includes form fields for all editable attributes of the user profile.
  3. Data entered by the user is validated client-side before being submitted.
  4. There is a clear and visible link from the user's profile page to the Edit page.
  5. The page handles invalid input gracefully and provides useful feedback to the user.
  6. The Edit page has been thoroughly tested and all bugs have been addressed.
image The form should be a basic ion-list ion-item some field format.

Need Unit Tests for AuthService File

Description

We need to create unit tests for our service file using Karma and Jasmine to ensure all functions behave as expected.

Service File Details

  • File Name: auth.service.ts
  • Location: src/app/services/auth.service.ts

Test Requirements

  • Write tests to cover all functions in the service file.
  • Each test should cover both the expected outcome and potential edge cases.

Steps to Start

  1. Navigate to the service file located at src/app/services/auth.service.ts
  2. Examine the functions that are currently without tests
  3. Begin writing tests in a separate auth.service.spec.ts file

Expected Outcome

All functions within the service file will have associated unit tests that cover both expected behavior and potential edge cases. All tests should pass when running the ng test command.

3: Implement Group Profile Model in Firebase

#7 #10

  1. Create Group Model:

    Start by defining a TypeScript interface for the Group Profile in your Ionic project. This should match the structure of the Group documents in your Firestore database.

    export interface Group {
        id: string;
        name: string;
        description: string;
        members: Array<string>; // this can store the user ids of the members
    }
  2. Extend Firestore Service:

    Extend your existing Firestore service (which you created for the User Profile) to include methods for creating, retrieving, updating, and deleting Group Profile documents.

    Here's an example of a getGroupProfile method, which retrieves a Group Profile document from Firestore:

    getGroupProfile(groupId: string) {
        return this.firestore.collection('groups').doc<Group>(groupId).valueChanges();
    }

    Implement similar methods for creating, updating, and deleting Group Profiles.

  3. Using the Firestore Service:

    You can now use this Firestore service in your Ionic components to interact with the Group Profile documents in your Firestore database.

As with the User Profile, be sure to handle any errors and edge cases that may occur, such as what happens if a document doesn't exist or if a network error occurs.

  1. Create User-Group Relationships:

    If you need to keep track of which users are members of which groups, you might consider creating a separate collection in Firestore for storing these relationships. Each document in this collection could store a user ID and a group ID, indicating that the user is a member of the group.

    Alternatively, you could include a list of user IDs in each Group document (as shown in the Group interface above), and/or a list of group IDs in each User document. The best approach depends on your specific needs and how you anticipate querying this data.

Configure Firebase environments for Dev and Prod

Description

We'll need to configure the Firebase server so that we can deploy the application into both prod and dev environments.

Motivation

In order to make the application functional and able to use future features such as authentication, we'll need to connect the app to firebase.

Proposed Solution (Optional)

Configure Two Environments

  1. dev - this is the environment that will be used to view the application as features are merged in and build out new features against.
  2. prod - this will be the stable version that will be used by user of the application.

17: Create Group Profile Edit Page

#7 #10

Description:

We need to provide group administrators with the ability to edit their group's profile information. This task involves designing and implementing a Group Profile Edit page. This page should be easily accessible, preferably directly linked from the group's profile page.

Tasks:

  1. UI Design

    • Design the layout of the Group Profile Edit page. The design should be intuitive and user-friendly, making it easy for administrators to locate and edit fields.
  2. Implement Edit Page

    • Implement the design in the front-end code. This will be a new page that includes form fields for all editable attributes of the group profile.
  3. Field Validation

    • Implement client-side validation to ensure the data entered by the administrator is valid before it is submitted.
  4. Link to Profile

    • Add a link or button on the group's profile page that leads to the Edit page. This link or button should only be visible to group administrators.
  5. Testing

    • Test the page with various inputs and ensure it handles invalid input gracefully.

Acceptance Criteria:

  1. The Group Profile Edit page has been implemented according to the provided design.
  2. The Edit page includes form fields for all editable attributes of the group profile.
  3. Data entered by the administrator is validated client-side before being submitted.
  4. There is a clear and visible link from the group's profile page to the Edit page for group administrators.
  5. The page handles invalid input gracefully and provides useful feedback to the administrators.
  6. The Edit page has been thoroughly tested and all bugs have been addressed.
image

12: Implement Group Management Functionality

Description:

We need to implement various functionalities to allow group management within our application. The key features to be implemented are as follows:

  1. Creating a Group: Users should be able to create a new group. The creator of the group automatically becomes the group's admin. While creating the group, users should be able to set the group name, description, and group avatar.

  2. Inviting Users to a Group: Group admins should be able to invite other users to their group. This can be implemented by adding a button or option on the group's page, which will open a form or modal where the admin can search for and select users to invite. An invitation can then be sent to the selected users.

  3. Accepting Group Invitations: Users should receive notifications of group invitations and should be able to accept them. Upon accepting the invitation, the user should be added to the group's members list.

  4. Managing Group Members: Group admins should have the ability to manage group members. This includes viewing a list of all group members, removing members, and promoting other members to admin status.

  5. Leaving a Group: Members should be able to leave a group at any time. If the member is an admin, they must assign a new admin before they can leave the group.

Acceptance Criteria:

  • A user can create a group with a name, description, and avatar.
  • Group admins can invite users to join the group.
  • Users can accept group invitations and become group members.
  • Group admins can view, remove, and promote members.
  • Members can leave a group.

Notes:

Integration with Firebase will be necessary for the backend aspects of these features. You'll need to design the database schema for groups, implement the backend logic for group operations, and create Firestore security rules to ensure that only authorized users can perform certain operations. For example, only admins should be able to invite users, remove members, or change group details, and only invited users should be able to join a group.

The front-end part of this feature will involve creating new UI components (like forms, modals, and lists), integrating these components with the Firebase functions you create, and ensuring a good user experience.

#7
image

Add AGPL-3.0 License Notice to Source Code Files

We need to add an AGPL-3.0 license notice to our source code files for legal and informational purposes. The notice should look something like this:

    Nonprofit Social Networking Platform: Allowing Users and Organizations to Collaborate.
    Copyright (C) 2023  ASCENDynamics NFP

    This file is part of Nonprofit Social Networking Platform.

    Nonprofit Social Networking Platform is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published
    by the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Nonprofit Social Networking Platform is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Nonprofit Social Networking Platform.  If not, see <https://www.gnu.org/licenses/>.

This notice should be added to the top of each source file in our project.

3. Create Firebase Authentication Service

Step 1: Create a new Angular Service

Open your terminal and navigate to the root directory of your Ionic project. Run the following command to create a new service:

ng generate service services/auth

This command will create a new service auth inside the services folder.

Step 2: Import Firebase Auth Methods and Types

Open auth.service.ts and import the necessary Firebase methods and types:

import { getAuth, createUserWithEmailAndPassword, signInWithEmailAndPassword, signOut } from 'firebase/auth';

Step 3: Initialize Firebase Auth

In AuthService, initialize auth with getAuth():

export class AuthService {
  auth = getAuth();
  // ...
}

Step 4: Implement Sign Up, Sign In, and Sign Out methods

Implement the following methods in AuthService:

// Sign up with email/password
async signUp(email: string, password: string) {
  try {
    const result = await createUserWithEmailAndPassword(this.auth, email, password);
    return result;
  } catch (error) {
    console.log(error);
    throw error;
  }
}

// Sign in with email/password
async signIn(email: string, password: string) {
  try {
    const result = await signInWithEmailAndPassword(this.auth, email, password);
    return result;
  } catch (error) {
    console.log(error);
    throw error;
  }
}

// Sign out 
async signOut() {
  try {
    await signOut(this.auth);
  } catch (error) {
    console.log(error);
    throw error;
  }
}

Step 5: Subscribe to Authentication State

Firebase provides an onAuthStateChanged method that you can use to listen for changes to the user's sign-in state:

import { onAuthStateChanged } from 'firebase/auth';

export class AuthService {
  auth = getAuth();

  constructor() {
    onAuthStateChanged(this.auth, (user) => {
      if (user) {
        // User is signed in.
      } else {
        // User is signed out.
      }
    });
  }
  
  // Other methods...
}

Your AuthService should now allow you to sign up, sign in, and sign out users using Firebase Authentication. You can use this service in any component by injecting it into the component's constructor. Make sure to handle errors appropriately in your components when calling these methods, as they can throw errors if the sign in, sign up, or sign out processes fail.

#2
#9

Create the Ionic 7 blank application

Description

We'll need to create the new application and push it up to the project repository.

Motivation

Getting the application started and into the repository is essential to building out this project.

Proposed Solution (Optional)

Additional Context (Optional)

7: Connect Group Profile UI with Firebase

#7 #10

  1. Install AngularFire:

    If you haven't done this already, you'll need to install AngularFire, the official Angular library for Firebase. You can do this with npm:

    npm install firebase @angular/fire
  2. Set up Firebase:

    You should have a Firebase project set up with the Firebase CLI installed and initialized. This will allow you to interact with your Firebase project directly from your development environment.

  3. Import AngularFireModule and AngularFireDatabaseModule:

    In your app.module.ts, import the AngularFireModule and AngularFireDatabaseModule and add them to your imports array:

    import { AngularFireModule } from '@angular/fire';
    import { AngularFireDatabaseModule } from '@angular/fire/database';
    
    // Firebase configuration object
    const firebaseConfig = {
      // your config here
    };
    
    @NgModule({
      imports: [
        // other imports
        AngularFireModule.initializeApp(firebaseConfig),
        AngularFireDatabaseModule
      ],
      // other properties
    })

    Make sure to replace the firebaseConfig object with your actual Firebase configuration. You can find this in the Firebase console under Project settings > General > Your apps > Firebase SDK snippet.

  4. Create a service to interact with Firebase:

    You'll need a service that interacts with Firebase to fetch and update data. If you don't already have one, create one with the Angular CLI:

    ng generate service group

    This will create a group.service.ts file. In this file, inject AngularFireDatabase in the constructor and create methods to get, update, and delete group data:

    import { Injectable } from '@angular/core';
    import { AngularFireDatabase } from '@angular/fire/database';
    
    @Injectable({
      providedIn: 'root'
    })
    export class GroupService {
    
      constructor(private db: AngularFireDatabase) { }
    
      getGroup(groupId: string) {
        return this.db.object(`/groups/${groupId}`).valueChanges();
      }
    
      // other methods
    }
  5. Fetch group data in the Group Profile page:

    In your group-profile.page.ts, inject your GroupService and fetch the group data in ngOnInit:

    import { Component, OnInit } from '@angular/core';
    import { GroupService } from '../services/group.service';
    
    @Component({
      selector: 'app-group-profile',
      templateUrl: './group-profile.page.html',
      styleUrls: ['./group-profile.page.scss'],
    })
    export class GroupProfilePage implements OnInit {
      group: any;
    
      constructor(private groupService: GroupService) { }
    
      ngOnInit() {
        this.groupService.getGroup('groupId').subscribe(group => {
          this.group = group;
        });
      }
    }

    Replace 'groupId' with the actual ID of the group whose profile you want to display.

  6. Display the group data in the template:

    In your group-profile.page.html, you can now use the group property to display the group data:

    <ion-header>
      <ion-toolbar>
        <ion-title>{{ group.name }}</ion-title>
      </ion-toolbar>
    </ion-header>
    
    <ion-content>
      <ion-card>
        <ion-card-header>
          <ion-card-title>{{ group.name }}</ion-card-title>
        </ion-card-header>
        <ion-card-content>
          <p>Description: {{ group.description }}</p>
          <!-- Display other group data here -->
          <p>Number of Members: {{ group.members.length }}</p>
          <p>Created At: {{ group.createdAt | date }}</p>
        </ion-card-content>
      </ion-card>
    </ion-content>

This displays the number of members and the creation date of the group, using Angular's built-in date pipe for formatting the date. You should replace members.length and createdAt with the actual properties of your group data.

  1. Implement update functionality:

    In your group.service.ts, add a method to update the group data:

    updateGroup(groupId: string, groupData: any) {
      return this.db.object(`/groups/${groupId}`).update(groupData);
    }

    Then in your group-profile.page.ts, create a method that calls this service method when the user wants to update the group data.

    updateGroup() {
      const groupData = {
        // The updated group data
      };
    
      this.groupService.updateGroup('groupId', groupData);
    }

    Again, replace 'groupId' with the actual ID of the group.

  2. Implement delete functionality:

    In your group.service.ts, add a method to delete the group data:

    deleteGroup(groupId: string) {
      return this.db.object(`/groups/${groupId}`).remove();
    }

    Then in your group-profile.page.ts, create a method that calls this service method when the user wants to delete the group.

    deleteGroup() {
      this.groupService.deleteGroup('groupId');
    }

    Remember to replace 'groupId' with the actual ID of the group.

This will create a basic interaction between your Group Profile UI and Firebase, allowing you to fetch, update, and delete data.

  1. Test your implementation:

    Now that you have implemented the Firebase integration, it's time to test it. Run your application and navigate to the Group Profile page. Check if the data is correctly fetched from Firebase and displayed in your UI. Try updating and deleting data to see if the changes are correctly reflected in Firebase.

Need Unit Tests for MenuService File

Description

We need to create unit tests for our service file using Karma and Jasmine to ensure all functions behave as expected.

Service File Details

  • File Name: menu.service.ts
  • Location: src/app/services/menu.service.ts

Test Requirements

  • Write tests to cover all functions in the service file.
  • Each test should cover both the expected outcome and potential edge cases.

Steps to Start

  1. Navigate to the service file located at src/app/services/menu.service.ts
  2. Examine the functions that are currently without tests
  3. Begin writing tests in a separate menu.service.spec.ts file

Expected Outcome

All functions within the service file will have associated unit tests that cover both expected behavior and potential edge cases. All tests should pass when running the ng test command.

13: Implement Profile Privacy Settings

Description:

Develop settings that enable users to dictate the visibility of their profiles. The users should have options to set their profiles as "Friends-only", "Public", or "Private".

Detailed Tasks:

  1. Design Privacy Settings in User Schema

    • Extend the user schema in Firebase to include a "privacySetting" field. This field should have three possible values: "Public", "Friends-only", and "Private".
  2. Update User Model

    • Update the user model to accommodate the new "privacySetting" field. Users should be able to update this field.
  3. Create Privacy Settings UI

    • Design and implement a user interface for changing privacy settings. This could be a section in the user's settings page with a dropdown or radio buttons to select the desired privacy setting.
  4. Integrate Privacy Settings UI with Firebase

    • Connect the privacy settings UI with Firebase. When a user updates their privacy setting, this should be saved to their user data in Firebase.
  5. Implement Privacy Checks in User Profile View

    • When displaying a user's profile, check the viewer's relationship to the profile owner and the owner's privacy setting. Based on these factors, decide whether or not to display the profile.
  6. Test Privacy Settings

    • Thoroughly test privacy settings functionality. Make sure all edge cases are covered and that privacy settings work as expected.
  7. Document Privacy Settings Implementation

    • Write up clear documentation on how the privacy settings were implemented. This documentation should serve as a guide for future developers who work on this feature.

Acceptance Criteria:

  1. Privacy Settings in User Schema

    • The user schema in Firebase includes a "privacySetting" field. This field can be set to "Public", "Friends-only", or "Private".
  2. Updated User Model

    • The user model includes the new "privacySetting" field. Users can update this field.
  3. Privacy Settings UI

    • The privacy settings UI is implemented as part of the user's settings page. It includes a dropdown or radio buttons for the user to select their privacy setting.
  4. Integration with Firebase

    • The privacy settings UI is successfully integrated with Firebase. Updates to the user's privacy setting in the UI are saved in Firebase.
  5. Privacy Checks

    • The application correctly checks the viewer's relationship to the profile owner and the owner's privacy setting when a user's profile is accessed. Depending on these factors, the application decides whether to display the profile or not.
  6. Testing

    • All privacy settings functionalities are thoroughly tested and work as expected. All edge cases are considered during testing.
  7. Documentation

    • Clear documentation is written on how the privacy settings are implemented. This documentation can be understood and followed by future developers working on this feature.
image

10: Implement User-to-User Interaction

#7 #10

{
  "senderId": "user1",
  "recipientId": "user2",
  "status": "accepted,rejected,pending",
  "timestamp": 1634246892543
}

Description:

We need to implement functionality that allows users to interact with each other. This includes the ability for users to send friend requests, accept friend requests, and view each other's profiles.

Tasks:

  1. Design the Friend Request Schema

    • Define a schema in Firebase for friend requests. This should include fields such as 'sender', 'receiver', and 'status' (to indicate whether the request is pending, accepted, or rejected).
  2. Implement Friend Request Creation

    • Add functionality for users to send friend requests. This could be a button on a user's profile page that, when clicked, creates a new document in the 'friendRequests' collection in Firebase.
  3. Implement Friend Request Acceptance

    • Add functionality for users to accept friend requests. This could be implemented as an 'Accept' button next to each pending request in the user's list of received friend requests. When clicked, this should update the status of the friend request in Firebase.
  4. Implement Friend Request Rejection

    • Similarly, add functionality for users to reject friend requests. This could be an 'Reject' button next to each pending request. When clicked, this should update the status of the friend request in Firebase.
  5. Display Friends in User Profiles

    • After a friend request is accepted, the two users should be added to each other's list of friends. This list should be displayed on the user's profile page.
  6. Implement Profile Viewing

    • Add functionality for users to view each other's profiles. The information displayed should depend on the viewer's relationship with the profile owner and the owner's privacy settings.
  7. Testing

    • Test all new functionalities thoroughly to ensure they work as expected.
  8. Documentation

    • Document how the user-to-user interaction functionalities are implemented.

Acceptance Criteria:

  1. Users can send friend requests to other users.
  2. Users can accept friend requests from other users.
  3. Users can reject friend requests from other users.
  4. Once a friend request is accepted, the two users are added to each other's list of friends.
  5. Users can view their friends' profiles.
  6. All new functionalities work correctly and are free of bugs.
  7. Clear and detailed documentation is written on how these functionalities are implemented.
image image

19: Connect Group Profile Edit Page with Firebase

#7 #10 #77

Description:

We need to establish a connection between our Group Profile Edit page and Firebase. The purpose of this task is to make sure that the current group profile data can be retrieved from Firebase, displayed on the Edit page, and when changes are made, the updated data is saved back to Firebase.

Tasks:

  1. Retrieve Group Profile Data

    • Develop a function that retrieves the current group's profile data from Firebase. This data should be displayed in the form fields on the Group Profile Edit page.
  2. Update Group Profile Data

    • Implement a function that gathers data from the form fields and sends it back to Firebase when the user hits the "Save Changes" button. This function should overwrite the current group profile data in Firebase.
  3. Error Handling

    • Incorporate robust error handling. If the operations to fetch or update data fail, the user should be presented with a clear error message.
  4. Testing

    • Rigorously test the integration, ensuring it handles various inputs and scenarios. Verify that all changes to the group profile data are accurately saved and reflected in Firebase.

Acceptance Criteria:

  1. The current group profile data is successfully fetched from Firebase and displayed in the form fields on the Group Profile Edit page.
  2. Any changes made on the Group Profile Edit page are saved to Firebase when the user clicks the "Save Changes" button.
  3. In case of a failure in fetch or update operations, relevant error messages are displayed to the user.
  4. All changes to the group profile data are accurately saved and reflected in Firebase.
  5. The integration has been thoroughly tested and all identified bugs have been addressed.
image

2. Install and Setup Firebase and AngularFire in Ionic Project

Step 1: Install Firebase and AngularFire

Open your terminal and navigate to the root directory of your Ionic project. Install Firebase and AngularFire2 by running the following commands:

npm install firebase @angular/fire --save

Step 2: Configure Firebase and AngularFire

Provide Firebase configuration in your Ionic project. This is usually done within your environment files (environment.ts and environment.prod.ts) located in the environments folder.

export const environment = {
  production: false,
  firebase: {
    apiKey: "api-key",
    authDomain: "project-id.firebaseapp.com",
    databaseURL: "https://project-id.firebaseio.com",
    projectId: "project-id",
    storageBucket: "project-id.appspot.com",
    messagingSenderId: "sender-id",
    appId: "app-id",
    measurementId: "G-measurement-id"
  }
};

Replace the properties in the firebase object with your actual Firebase configuration.

Step 3: Import AngularFireModule and Environment into main.ts

- Import `initializeApp` from `firebase/app` and `environment` from your environments file at the top of your `main.ts` file like this:
```typescript
import { initializeApp } from 'firebase/app';
import { environment } from './environments/environment';
```

Step 4: Initialize Firebase:

In the bootstrapApplication function, add the Firebase initialization code inside the .then() block like this:

```typescript

  // Initialize Firebase before the application has been bootstrapped
  initializeApp(environment.firebaseConfig);
  
bootstrapApplication(AppComponent, {
  providers: [
    {provide: RouteReuseStrategy, useClass: IonicRouteStrategy},
    importProvidersFrom(IonicModule.forRoot({})),
    provideRouter(routes),
  ],
});
```
- This code will initialize Firebase with your configuration after the application has been bootstrapped.
  1. Test the changes:
    • Run your application and ensure that Firebase is correctly initialized and working as expected.

#2 Parent Issue
#9 Discussion

Implement Organizational Structures and Hierarchies within Groups

Description

This feature involves the creation of structures and hierarchies within groups that represent organizations on our platform. This includes the ability to represent different roles like Board Member, Volunteer, Worker, etc., and to facilitate communication and collaboration on projects and events within these structures.

Motivation

This feature is key for replicating real-world organizational structures in our platform, which will allow for more efficient collaboration and communication among group members. By clearly defining roles and hierarchies, we can ensure that information flow and task delegation are handled as effectively as possible.

Proposed Solution (Optional)

  1. Implement a feature that allows groups to define roles (e.g., Board Member, Volunteer, Worker) for their members.
  2. Enable the creation of hierarchies within these roles to reflect the organization's structure.
  3. Develop a communication feature that respects these hierarchies and roles, allowing for efficient collaboration and information flow.
  4. Ensure privacy settings and controls are in place for different roles and levels in the hierarchy.

Tasks

  1. Design a UI for creating and managing roles within a group.
  2. Develop the backend logic for managing these roles and their associated permissions.
  3. Implement a communication feature that considers the group's hierarchy and roles.
  4. Test the new features with different user roles and hierarchies.

Acceptance Criteria

  1. Users can create and manage roles within a group.
  2. Users can define a hierarchy of roles within a group.
  3. The communication feature respects the hierarchy and roles within a group.
  4. All new features have been tested and work as expected.

Additional Context (Optional)

This feature is part of our goal to make the platform more user-friendly and representative of real-world organizations. It's crucial that we discuss this in more detail to define the specifics of the design and functionality, including the level of flexibility we want to offer groups in defining their hierarchies and roles.

Feedback and suggestions are welcome and appreciated as we move forward with this idea.

5. Implement Login Functionality

  1. Create a Login Form:

    • In your login component (let's call it login.component.ts), create a login form similar to the signup form using Angular's FormGroup and FormControl.

    • Import the necessary dependencies:

      import { FormBuilder, Validators } from '@angular/forms';
    • In your component's constructor, initialize your form:

      constructor(private fb: FormBuilder) { }
      
      loginForm = this.fb.group({
        email: ['', [Validators.required, Validators.email]],
        password: ['', [Validators.required, Validators.minLength(6)]],
      });
    • This creates a form with two fields, email and password, with appropriate validators.

  2. Inject AuthService:

    • Import and inject the AuthService that you created earlier.

      import { AuthService } from '../services/auth.service';
      
      constructor(private fb: FormBuilder, private authService: AuthService) { }
  3. Implement Login Method:

    • Create a login method in your component that calls the signIn method from AuthService:

      async login() {
        const { email, password } = this.loginForm.value;
        try {
          const user = await this.authService.signIn(email, password);
          console.log(user);
        } catch (error) {
          console.log(error);
        }
      }
  4. Update Login Template:

    • In your login component's template (let's call it login.component.html), bind the form controls to input fields:

      <form [formGroup]="loginForm" (ngSubmit)="login()">
        <label>
          Email:
          <input type="email" formControlName="email">
        </label>
        <label>
          Password:
          <input type="password" formControlName="password">
        </label>
        <button type="submit">Log In</button>
      </form>
    • This binds your email and password form controls to the corresponding input fields, and binds the form's submit event to your login method.

  5. Test Login Functionality:

    • Now you can test your login functionality. Run your Ionic app, navigate to your login page, enter the email and password of a user you signed up, and click the Log In button. If everything is set up correctly, the user should be logged in, and the user information should be logged to the console.

Just like with the signup functionality, make sure to handle errors and edge cases appropriately in your actual application. The above implementation is a basic example and may not cover all scenarios.

#2
#9

1: Design Database Schema for User and Group Profiles

#7 #10

  1. Understand Firestore Data Model: Firestore is a NoSQL document-oriented database. It stores data in documents, which are stored in collections. Each document can contain complex nested objects. Make sure you have a good understanding of Firestore and NoSQL databases before you start.

  2. Identify Data Requirements: You need to decide what information to store for each user and group profile. At a minimum, you might want to store for a user:

    • User ID
    • User Name
    • Email
    • Profile Picture
    • Bio

    And for a group:

    • Group ID
    • Group Name
    • Group Picture
    • Description
    • Members (a list of User IDs)
  3. Design Data Structure: Based on the above requirements, you would create two collections in Firestore: users and groups. Each user would be a document in the users collection, and each group would be a document in the groups collection.

    For the users collection, the document structure might be:

    {
        id: 'user-id',
        name: 'user-name',
        email: 'user-email',
        profilePicture: 'url-to-profile-picture',
        bio: 'user-bio'
    }

    And for the groups collection:

    {
        id: 'group-id',
        name: 'group-name',
        groupPicture: 'url-to-group-picture',
        description: 'group-description',
        members: ['user-id1', 'user-id2']
    }
  4. Security Rules: Remember to set up Firestore Security Rules to ensure only authorized users can read/write data to the database. At a minimum, you would want users to be able to read their own data and write only to their own user document. For the groups, you might want all users to be able to read group data, but only group members can write to the group document.

  5. Test Your Database: Use the Firebase console to manually add some data to your database and check if it's working as expected.

Note: This is a simple schema design. Depending on your application's requirements, you might need to normalize/de-normalize your data, add more collections/documents, or use Firestore transactions to ensure data consistency. Always design your database schema based on your application's data access patterns.

POC 10: Implement User-to-User Interaction

Description

#38
This is going to be used to create a component that has all the functionality in #38 so that we can build these features before UX is able work on the Wireframes.

Motivation

I want to identify the challenges of creating this feature an address any bottlenecks before they become a bigger issue when working with friend requests.

Proposed Solution (Optional)

We build out a component that allows us to create friend type requests. Accept or Reject those request, so that we can demo that this feature works as expected and the code can be reused in the design that UX designers determine will work best.

Additional Context (Optional)

image

Update the Information in PROJECT_GOALS.md

Description

Replace the information in PROJECT_GOALS.md file with the information provided below.

Location

PROJECT_GOALS.md

Proposed Changes (Optional)

### Ascend Co-op Platform Project Goals

## Introduction

The Ascend Co-op Platform project aims to create an open-source platform that empowers communities to form, manage, and collaborate amongst their own organizations. The platform is designed to facilitate pro-labor, collaborative, and organizing features to enhance positive community impact.

## Goals

1. **Community Empowerment**: Develop a platform that enables communities to create and manage their own organizations, fostering a sense of ownership and active participation.
2. **Inter-organizational Collaboration**: Facilitate seamless collaboration between various organizations formed within the platform. This will promote synergy and collective growth amongst participating groups.
3. **Open Source**: Uphold an open-source approach to allow community contributions, ensuring the platform benefits from diverse inputs and continuous improvements.
4. **Pro-Labor and Organizing Features**: Incorporate features that promote pro-labor practices, enhance collaboration, and provide effective organizing tools. This will further amplify the platform's positive impact on the community.
5. **Testing and Quality Assurance**: Ensure high-quality code through comprehensive testing strategies, continuous integration, and continuous deployment processes.
6. **Community Engagement**: Encourage and manage contributions from the community through clear contribution guidelines, good documentation, and efficient communication channels such as GitHub discussions.
7. **Coding Standards**: Adhere to established coding standards, including ESLint and Prettier rules for JavaScript/TypeScript, to maintain clean, readable, and maintainable code.

## Non-Goals

The project will not focus on the following:

1. **Monetization**: As a non-profit initiative, the project will not engage in monetization strategies.
2. **Platform-Specific Development**: The project aims to be platform-agnostic, accessible from any modern web browser, and will not develop platform-specific applications (iOS, Android, Windows, etc.) at the current stage.

8. Add Google Authentication

Issue Description

We want to incorporate Google authentication into our Ionic Angular app. The application already has an auth.service file and configurations set for Google authentication. Now, we need to update our user-login page to provide users with the option to sign in using their Google account.

Steps

  1. Add GoogleAuthProvider import in auth.service.ts

    At the top of your auth.service.ts file, import GoogleAuthProvider, getAuth and signInWithPopup from firebase/auth as follows:

    import { GoogleAuthProvider, getAuth, signInWithPopup } from "firebase/auth";
  2. Create Google provider instance in auth.service.ts

    Inside the auth.service.ts file, create a new instance of GoogleAuthProvider. You can do this inside the constructor or a specific method depending on your setup:

    const provider = new GoogleAuthProvider();
  3. Create signInWithGoogle method in auth.service.ts

    Still within the auth.service.ts file, define a new method signInWithGoogle. This method will be responsible for initiating the Google authentication process:

    signInWithGoogle() {
      const auth = getAuth();
      return signInWithPopup(auth, this.provider)
        .then((result) => {
          // This gives you a Google Access Token. You can use it to access the Google API.
          const credential = GoogleAuthProvider.credentialFromResult(result);
          const token = credential.accessToken;
          // The signed-in user info.
          const user = result.user;
          // return or process user data as needed
        })
        .catch((error) => {
          // Handle Errors here.
          const errorCode = error.code;
          const errorMessage = error.message;
          // The email of the user's account used.
          const email = error.email;
          // The AuthCredential type that was used.
          const credential = GoogleAuthProvider.credentialFromError(error);
          // return or process error data as needed
        });
    }
  4. Add Google Sign In button in user-login component

    In your user-login component HTML file, add a new button for Google Sign In. This button will call the signInWithGoogle method from the auth service when clicked:

    <ion-button
      type="button"
      expand="block"
      color="danger"
      (click)="signInWithGoogle()"
    >
      <ion-icon name="logo-google" slot="start"></ion-icon>
      Sign In with Google
    </ion-button>
  5. Add signInWithGoogle method in user-login component

    In your user-login component TypeScript file, add a new method signInWithGoogle that will call the signInWithGoogle method from the auth service:

    signInWithGoogle() {
      this.authService.signInWithGoogle()
        .then(user => {
          // handle successful sign in
        })
        .catch(error => {
          // handle sign in error
        });
    }

Acceptance Criteria

  1. User is presented with an option to Sign In with Google on the login page.
  2. Clicking on "Sign In with Google" should initiate the Google authentication process.
  3. Successful Google authentication should return user information.
  4. Failed Google authentication should return an appropriate error message.

Update Project License from MIT to AGPL

Description:

As part of our ongoing efforts to ensure the openness and freedom of our software, we have decided to update our project license from the Massachusetts Institute of Technology (MIT) License to the Affero General Public License (AGPL). The AGPL offers more protection against the software being used in a proprietary program as it requires any modifications to the software be made available to the network users interacting with it, even if those users are interacting with the software over a network.

Tasks:

  1. Review the current MIT LICENSE file and understand the implications of moving from MIT to AGPL.
  2. Remove or archive the current LICENSE file.
  3. Create a new LICENSE file and copy the AGPL text into it.
  4. Update the README and any other relevant documentation to reflect the change in license.
  5. Commit the changes with a message like "Updated license from MIT to AGPL"
  6. Open a pull request for the changes to be reviewed and merged.

Difficulty: Easy

Skills Required:

  • Basic understanding of software licenses
  • Familiarity with git and GitHub

Additional Resources:

18: Connect User Profile Edit Page with Firebase

#7 #10 #77

Description:

We need to integrate our User Profile Edit page with Firebase. This task involves writing the necessary code to fetch current user profile data from Firebase, display it on the edit page, and send the edited data back to Firebase when the user saves their changes.

Tasks:

  1. Fetch User Profile Data

    • Write a function to fetch the current user's profile data from Firebase and display it in the form fields on the User Profile Edit page.
  2. Update User Profile Data

    • Write a function to collect the data from the form fields and send it to Firebase when the user clicks the "Save Changes" button. This should overwrite the current user profile data in Firebase.
  3. Error Handling

    • Implement appropriate error handling. If the fetch or update operations fail, the user should see a clear error message.
  4. Testing

    • Test the integration thoroughly with various inputs and scenarios. Make sure all changes to the user profile data are accurately reflected in Firebase.

Acceptance Criteria:

  1. Current user profile data is fetched from Firebase and displayed in the form fields on the User Profile Edit page.
  2. Changes made on the User Profile Edit page are saved to Firebase when the user clicks the "Save Changes" button.
  3. Appropriate error messages are displayed if the fetch or update operations fail.
  4. All changes to the user profile data are accurately reflected in Firebase.
  5. The integration has been thoroughly tested and all bugs have been addressed.

Implement Social Network Style User and Group Profiles for MVP

Description

Our platform currently lacks a dedicated space for users to express their identities and for groups to share their purposes and updates. This deficiency can result in less user engagement and poor community building.

Motivation

  1. Enhanced User Engagement: Personalized profiles can foster a sense of ownership among users, encouraging them to engage more with the platform.
  2. Community Building: Group profiles can serve as a central hub for members, promoting more efficient communication and collaboration.
  3. User-Friendly: By emulating well-known social media platforms like Facebook and LinkedIn, we can provide a familiar user experience that's easy to navigate.

Proposed Solution (Optional)

We should implement social network-style profiles for both individual users and groups. For individuals, the profile page should include their details, activity, and connections. For groups (which can represent organizations), the profile should include details about the organization, its members, and its activities.

Additional Context (Optional)

Tasks:

  1. Design the layout for individual and group profiles.
  2. Implement the front-end elements for these profiles.
  3. Integrate the back-end to populate profile data.
  4. Ensure privacy settings and controls are in place.
  5. Conduct thorough testing to ensure functionality and usability.

Acceptance Criteria:

  1. Users can create and personalize their profiles.
  2. Organizations can create and manage their group profiles.
  3. Users can view and interact with their own and others' profiles within the bounds of their privacy settings.
  4. All profile data is accurately represented and updated in real-time.

Let's discuss this further to finalize the design and functionality specifics. Feedback and suggestions are more than welcome.

Kind regards,
@mufniarz

7. Implement User Status Tracking

Step 1: Import necessary Firebase methods

In your auth.service.ts, make sure you have imported the onAuthStateChanged method from Firebase:

import { onAuthStateChanged } from 'firebase/auth';

Step 2: Create a BehaviorSubject for user status

In your AuthService, create a BehaviorSubject to keep track of the current user. A BehaviorSubject is a type of subject that can emit the current value to new subscribers:

import { BehaviorSubject } from 'rxjs';

export class AuthService {
  auth = getAuth();
  private currentUserSubject = new BehaviorSubject(null);
  currentUser$ = this.currentUserSubject.asObservable();
  // ...
}

Step 3: Implement User Status Tracking

Use the onAuthStateChanged method to listen for changes in the user's authentication status. When the status changes, update currentUserSubject:

constructor() {
  onAuthStateChanged(this.auth, (user) => {
    if (user) {
      // User is signed in.
      this.currentUserSubject.next(user);
    } else {
      // User is signed out.
      this.currentUserSubject.next(null);
    }
  });
}

Step 4: Implement a method to get the current user

This method will return the value of currentUserSubject, which is the current user:

getCurrentUser() {
  return this.currentUserSubject.value;
}

With these changes, your AuthService can now track the user's authentication status. Any component can subscribe to currentUser$ to reactively respond to changes in the user's authentication status. For example, you can use it to show or hide certain UI elements based on whether the user is signed in.

#2
#9

Structure Utility/Helper Files for Data Creation and Modification in Firestore

#83 #82

Description:

In order to keep track of data changes, we need to create utility/helper functions that append certain fields (i.e., createdBy, createdDate, lastModifiedBy, and lastModifiedDate) before creating or updating data in the Firestore. These functions should be reusable, well-documented, and tested.

Steps:

  1. Create a utilities directory:
    Create a new directory for utilities, where we will add all utility/helper functions.

  2. Create a helper file:
    Add a TypeScript file for Firebase data manipulation, e.g., firebase.util.ts.

  3. Write utility functions:
    Write utility functions with clear, concise names and document their usage.

Here is an example of how to structure utility functions for Firestore data manipulation:

// utilities/firebase.util.ts
import { AngularFirestore } from '@angular/fire/firestore';

// Preparing data before creating a new document in Firestore
export function prepareDataForCreate(db: AngularFirestore, data: any, userId: string) {
  const timestamp = db.firestore.FieldValue.serverTimestamp();
  return {
    ...data,
    createdBy: userId,
    createdDate: timestamp,
    lastModifiedBy: userId,
    lastModifiedDate: timestamp,
  };
}

// Preparing data before updating an existing document in Firestore
export function prepareDataForUpdate(db: AngularFirestore, data: any, userId: string) {
  const timestamp = db.firestore.FieldValue.serverTimestamp();
  return {
    ...data,
    lastModifiedBy: userId,
    lastModifiedDate: timestamp,
  };
}

Remember to import AngularFirestore in the providers array when bootstrapping your application.

Acceptance Criteria:

  • Utility/helper functions must be reusable across different components.
  • Each function should be well-documented, explaining what it does and how to use it.
  • All utility/helper functions must be tested to ensure they work correctly.

Note:

The structure and number of utility/helper files may vary depending on the requirements of your application. Always aim for clean, maintainable, and self-explanatory code.

20: Implement UI/UX Improvements Based on User Feedback

#7 #10

Description:

Once we have implemented the initial features, it's crucial to gather user feedback and make the necessary UI/UX improvements. The goal is to ensure that our application is intuitive, user-friendly, and meets the needs of our users effectively.

Tasks:

  1. Gather User Feedback

    • Create a structured method for gathering feedback from users about their experience with our application. This could include surveys, feedback forms, or user interviews.
  2. Analyze User Feedback

    • Review and analyze the user feedback received. Identify common themes and issues. Create a priority list based on the frequency and impact of the identified issues.
  3. Plan Improvements

    • Develop a plan for making the necessary improvements based on user feedback. For complex changes, this may involve creating mock-ups or prototypes.
  4. Implement Improvements

    • Implement the changes in the codebase. This may include updating layouts, refining interactions, fixing bugs, improving performance, etc.
  5. Testing and Review

    • Thoroughly test all changes to ensure they work as expected. Get feedback on the changes from the original users who reported the issues, if possible.

Acceptance Criteria:

  1. User feedback has been systematically collected and analyzed.
  2. A plan for UI/UX improvements based on user feedback has been developed.
  3. The planned improvements have been successfully implemented in the application.
  4. All changes have been thoroughly tested, and they work as expected.
  5. Users who provided the original feedback agree that the implemented changes address their concerns.

Add Multi-Language Support for the Application

#83 #82

Description:

To make our application accessible and user-friendly for a global audience, we need to implement multi-language support. This involves the following steps:

Steps:

  1. Set up i18n:
    Internationalization (i18n) is the process of designing and preparing your app to be usable in different languages. We need to set up the i18n file structure and include English as the default language to start.

  2. Add new language files:
    Add new JSON files for each language we want to support. The JSON file should include key-value pairs where the key is a unique identifier and the value is the translated text.

  3. Create a language service:
    The language service should include methods for setting the current language and getting the translated text.

  4. Implement language selector:
    Provide a way for the user to select their preferred language.

Here are the code snippets for each step:

  1. Set up i18n:
// i18n/en.json
{
  "welcome_message": "Welcome to our application!",
  "logout": "Logout"
}
  1. Add new language files:
// i18n/fr.json
{
  "welcome_message": "Bienvenue dans notre application!",
  "logout": "Se déconnecter"
}
  1. Create a language service:
// language.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';

@Injectable({ providedIn: 'root' })
export class LanguageService {
  private currentLang = 'en';

  constructor(private http: HttpClient) {}

  setLanguage(language: string): void {
    this.currentLang = language;
  }

  translate(key: string): Observable<string> {
    return this.http.get(`i18n/${this.currentLang}.json`).pipe(
      map((translations: {[key: string]: string}) => translations[key] || key),
      catchError(() => of(key))
    );
  }
}
  1. Implement language selector:
// language-selector.component.ts
import { Component } from '@angular/core';
import { LanguageService } from './language.service';

@Component({
  selector: 'app-language-selector',
  template: `
    <select (change)="changeLanguage($event.target.value)">
      <option value="en">English</option>
      <option value="fr">French</option>
      <!-- Add more options as needed -->
    </select>
  `
})
export class LanguageSelectorComponent {
  constructor(private languageService: LanguageService) {}

  changeLanguage(language: string) {
    this.languageService.setLanguage(language);
  }
}

Remember to include HttpClientModule in the providers array when bootstrapping your application to make HTTP requests.

Acceptance Criteria:

  • The application must support multiple languages.
  • The user must be able to switch languages at any time.
  • The selected language should persist across different pages and sessions.
  • All text displayed to the user must be translated based on the selected language.

Note:

Add the paths for new language files when they are created. It would be a good idea to add tests to verify that the translations are working correctly.

9: Implement Group Search Functionality

#7 #10

  1. Install AngularFire and Firebase

    If not done already, you will need to install Firebase and AngularFire in your project. AngularFire is the official Angular library for Firebase, and it will make working with Firebase in Angular much easier.

    You can install both with npm:

    npm install firebase @angular/fire

    Make sure to setup Firebase in your project and initialize it with your Firebase project credentials.

  2. Create a Group Service

    Create a service that will handle all group-related operations, including the search.

    ng generate service services/group

    This will create a group.service.ts file in your services directory.

  3. Implement the Search Method

    In group.service.ts, import AngularFireDatabase and inject it in the constructor.

    import { AngularFireDatabase } from '@angular/fire/database';
    
    constructor(private db: AngularFireDatabase) {}

    Then, add a method to perform the search:

    searchGroups(start, end): Observable<any[]> {
      return this.db.list('/groups', ref =>
        ref.orderByChild('groupName').startAt(start).endAt(end)
      ).valueChanges();
    }

    This will return an Observable of groups whose group names are between the start and end parameters.

  4. Create the Search UI

    In your search component, add an input field for the search term and a button to perform the search.

    <input [(ngModel)]="searchTerm" placeholder="Search groups">
    <button (click)="search()">Search</button>

    Implement the search method in your component's TypeScript file:

    searchTerm = '';
    
    constructor(private groupService: GroupService) {}
    
    search() {
      this.groupService.searchGroups(this.searchTerm, this.searchTerm + '\uf8ff')
        .subscribe(groups => {
          // Do something with the groups
        });
    }

    Note that '\uf8ff' is a very high Unicode character which will match all strings that start with the search term.

  5. Test Your Search

    After implementing the above steps, you should be able to search groups by their group name. Input a group name in the search field and click the Search button. You should see a list of groups that match the search term.

6: Connect User Profile UI with Firebase

#7 #10

  1. Create a new page:

    Use the Ionic CLI to generate a new page for the Group Profile:

    ionic generate page GroupProfile

    This will create a new folder under src/app/group-profile with four files: group-profile.page.html (the template), group-profile.page.scss (the styles), group-profile.page.ts (the class), and group-profile.page.spec.ts (the test).

  2. Design the template:

    Open group-profile.page.html and start designing your Group Profile page. You might want to display the group's name, description, and any other relevant information.

    Here's a simple example:

    <ion-header>
      <ion-toolbar>
        <ion-title>Group Profile</ion-title>
      </ion-toolbar>
    </ion-header>
    
    <ion-content>
      <ion-card>
        <ion-card-header>
          <ion-card-title>{{ group.name }}</ion-card-title>
        </ion-card-header>
        <ion-card-content>
          <p>Description: {{ group.description }}</p>
          <!-- Include other group details here -->
        </ion-card-content>
      </ion-card>
    </ion-content>
  3. Update the class:

    In group-profile.page.ts, you'll need to fetch the group's data from Firestore and assign it to a property in your class. This property can then be used in your template to display the group's data.

    Here's an example:

    import { Component, OnInit } from '@angular/core';
    import { FirestoreService } from '../services/firestore.service';
    
    @Component({
      selector: 'app-group-profile',
      templateUrl: './group-profile.page.html',
      styleUrls: ['./group-profile.page.scss'],
    })
    export class GroupProfilePage implements OnInit {
      group: any;
    
      constructor(private firestoreService: FirestoreService) { }
    
      ngOnInit() {
        this.firestoreService.getGroupProfile('groupId').subscribe(group => {
          this.group = group;
        });
      }
    }

    Note that 'groupId' should be replaced with the actual ID of the group whose profile you want to display. How you get this ID will depend on your application's routing and authentication setup.

  4. Style the page:

    You can use the SCSS file group-profile.page.scss to add styles to your Group Profile page. The Ionic framework provides a variety of CSS utilities and pre-built components that you can use to design your page.

  5. Test the page:

    Finally, make sure to test your page both in a web browser and on a mobile device to ensure it looks and behaves as expected. Remember to handle any edge cases, such as what should be displayed if the group's data fails to load.

  6. Route to the Group Profile Page:

    In your app-routing.module.ts, add a route to your group profile page.

    const routes: Routes = [
      // other routes
      {
        path: 'group-profile',
        loadChildren: () => import('./group-profile/group-profile.module').then(m => m.GroupProfilePageModule)
      }
    ];

    Now, you can navigate to this page from any other page by using the Angular router:

    this.router.navigate(['/group-profile']);

10. Protect Routes Based on Authentication Status

Step 1: Create a new Angular Service for the Guard

Open your terminal and navigate to the root directory of your Ionic project. Run the following command to create a new service:

ng generate service services/authGuard

Step 2: Implement CanActivate in the Guard Service

Open authGuard.service.ts and implement the CanActivate interface. You will also need to inject AuthService and Router into this service:

import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { map, take } from 'rxjs/operators';
import { AuthService } from './auth.service';

@Injectable({
  providedIn: 'root'
})
export class AuthGuardService implements CanActivate {

  constructor(private authService: AuthService, private router: Router) { }

  canActivate(): Observable<boolean> {
    return this.authService.user$.pipe(
      take(1),
      map(user => !!user), // map to boolean
      tap(loggedIn => {
        if (!loggedIn) {
          console.log('Access denied');
          this.router.navigate(['/login']);
        }
      })
    );
  }
}

In this service, the canActivate() function subscribes to AuthService.user$ (which is an Observable of the user's Firebase User object). If the user is logged in, user$ will emit a User object and the map() operator will map it to true; if the user is not logged in, user$ will emit null and map() will map it to false. The tap() operator is used to navigate to the login page if the user is not logged in.

Step 3: Use the Guard in the Router Configuration

In your app.routing.ts file, you can now use the AuthGuardService to protect your routes. To do this, add a canActivate property to the route configuration of the routes you want to protect, and set it to an array that contains AuthGuardService:

import { AuthGuardService } from './services/authGuard.service';

const routes: Routes = [
  {
    path: 'protected',
    component: ProtectedComponent,
    canActivate: [AuthGuardService]
  },
  // other routes...
];

Now, when a user tries to navigate to the protected route, the AuthGuardService.canActivate() function will be called. If this function returns true, navigation will continue; if it returns false, navigation will be cancelled and the user will be redirected to the login page.

#2 #9

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.