Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Partner Blog Post Submission] E-Learning Platforms with Strapi #1532

Open
ZanMarPag opened this issue Aug 23, 2024 · 11 comments
Open

[Partner Blog Post Submission] E-Learning Platforms with Strapi #1532

ZanMarPag opened this issue Aug 23, 2024 · 11 comments
Assignees

Comments

@ZanMarPag
Copy link

My Request

Company name: Pagepro
Title: Scalable E-Learning Platforms with Strapi’s API Integrations
Outline:

  1. Introduction - Increasing e-learning platform popularity
  2. Main challenges for e-learning platform providers
  3. How Strapi Enables Smooth Integrations for E-Learning Platforms
  • Automated Course Access Management
  • Real-Time Data Synchronization with Marketing Tools
  • Community Building through Discord Integration
  • Adding Value through External Partnerships
  1. Outcomes and Benefits of Strapi Integrations

The article would be based on our project: https://pagepro.co/case-studies/learn-squared

Thank you.

@vcoisne vcoisne changed the title [Partner Blog Post Submission] [Partner Blog Post Submission] E-Learning Platforms with Strapi Aug 28, 2024
@vcoisne
Copy link
Contributor

vcoisne commented Aug 28, 2024

Hi @ZanMarPag it seems like a great topic. Please go ahead and feel free to submit a draft.

@ZanMarPag
Copy link
Author

ZanMarPag commented Aug 30, 2024 via email

@PaulBratslavsky
Copy link
Contributor

@ZanMarPag I reviewed the article and think the draft is off to a great start. However, I believe it would benefit from more context, particularly with code examples showing how to integrate the Strapi API.

For these types of articles, our audience—mainly developers—typically looks for small demo projects or code integration examples. They want to understand the process in more detail.

Please let me know if you have any questions!

@ZanMarPag
Copy link
Author

ZanMarPag commented Sep 6, 2024 via email

@ZanMarPag
Copy link
Author

ZanMarPag commented Sep 10, 2024 via email

@ZanMarPag
Copy link
Author

ZanMarPag commented Sep 17, 2024 via email

@ZanMarPag
Copy link
Author

ZanMarPag commented Sep 24, 2024 via email

@Theodore-Kelechukwu-Onyejiaku
Copy link
Collaborator

Hi @ZanMarPag ,

Your article looks great. However, I have some few suggestions.

  • Please replace code images with actual codes using code blocks. You can trying using HackMd instead of Google docs for this. This is so that codes can be copied and pasted to a code editor to run and test.
  • Please provide a Github repo if necessary.

Thank you.

@ZanMarPag
Copy link
Author

ZanMarPag commented Nov 6, 2024 via email

@Theodore-Kelechukwu-Onyejiaku
Copy link
Collaborator

Hi @ZanMarPag, please you can share them here on Github if you are not conversant with HackMD. The main reason is so that I could have a Mardown Format of your content.

You can start by adding the codes between backticks. Surround codes with 3 backticks at the top and 3 backticks at the bottom.

See the image below:

Screenshot 2024-11-21 at 8 26 03 PM

@ZanMarPag
Copy link
Author

Hi, okay, thanks a lot for your answer, I paste the codes below:

import axios, { AxiosError } from 'axios';
interface Course {
  id: number;
  title: string;
  lessons: {
    title: string;
    duration: number;
  }[];
  instructor: {
    name: string;
    bio: string;
  };
}

const apiUrl = process.env.STRAPI_API_URL ?? 'https://default-strapi-api-url.com';

async function fetchCourses(): Promise<Course[]> {
  try {
    const response = await axios.get<Course[]>(`${apiUrl}/api/courses`);
    console.log('Courses: ', response.data);
    return response.data;
  } catch (error: unknown) {
    if (axios.isAxiosError(error)) {
      console.error(`Error fetching courses: ${error.response?.status} - ${error.response?.statusText}`);
    } else {
      console.error('Unknown error occurred', error);
    }
    throw new Error('Failed to fetch courses');
  }
}
import axios, { AxiosResponse } from 'axios';

interface Lesson {
  title: string;
  duration: number;
}

interface Instructor {
  name: string;
  bio: string;
}

interface Course {
  id: number;
  title: string;
  lessons: Lesson[];
  instructor: Instructor;
}

async function fetchCourses(): Promise<Course[]> {
  const query = `
    query {
      courses {
        id
        title
        lessons {
          title
          duration
        }
        instructor {
          name
          bio
        }
      }
    }
  `;

  try {
    const response: AxiosResponse<{ data: { courses: Course[] } }> = await axios.post(
      `${process.env.STRAPI_API_URL}/graphql`,
      {
        query,
      }
    );

    const courses = response.data.data.courses;
    console.log('Courses: ', courses);
    return courses;
  } catch (error: any) {
    console.error('Error fetching courses:', error.message);
    throw new Error('Failed to fetch courses');
  }
}
import { Context } from 'koa';
import axios from 'axios';

interface ShopifyWebhookData {
  event_type: string;
  data: {
    customer: {
      email: string;
    };
    line_items: {
      product_id: number;
    }[];
  };
}

export default {
  async webhook(ctx: Context): Promise<void> {
    const { event_type, data }: ShopifyWebhookData = ctx.request.body;

    // Validate incoming request data
    if (!data || !event_type || !data.customer || !data.line_items || data.line_items.length === 0) {
      ctx.throw(400, 'Invalid request data');
      return;
    }

    if (event_type === 'order_created') {
      const userEmail: string = data.customer.email;
      const courseId: number = data.line_items[0].product_id;

      // Perform user and course queries in parallel to optimize performance
      try {
        const [user, course] = await Promise.all([
          strapi.query('user').findOne({ email: userEmail }),
          strapi.query('course').findOne({ id: courseId })
        ]);

        if (!user) {
          ctx.throw(404, `User with email ${userEmail} not found`);
          return;
        }

        if (!course) {
          ctx.throw(404, `Course with ID ${courseId} not found`);
          return;
        }

        // Create course enrollment after successful queries
        await strapi.query('course-enrollment').create({
          data: {
            user: userEmail,
            course: courseId,
          }
        });

        ctx.send({ message: 'Course access granted' });
      } catch (error: any) {
        // Log the error for further debugging
        console.error('Error processing webhook:', error.message);
        ctx.throw(500, 'Error processing webhook');
      }
    } else {
      ctx.throw(400, `Unhandled event type: ${event_type}`);
    }
  }
};
import axios, { AxiosError } from 'axios';

interface UserData {
  email: string;
  firstName: string;
  lastName: string;
}

async function syncToMailchimp(userData: UserData): Promise<void> {
  // Validate environment variables
  const mailchimpApiUrl = process.env.MAILCHIMP_API_URL;
  const mailchimpListId = process.env.MAILCHIMP_LIST_ID;
  
  if (!mailchimpApiUrl || !mailchimpListId) {
    throw new Error('Mailchimp API URL or List ID is not defined in the environment variables');
  }

  try {
    const response = await axios.post(`${mailchimpApiUrl}/lists/${mailchimpListId}/members`, {
      email_address: userData.email,
      status: 'subscribed',
      merge_fields: {
        FNAME: userData.firstName,
        LNAME: userData.lastName,
      }
    });

    // Log success response from Mailchimp (Optional)
    console.log(`Mailchimp sync successful for ${userData.email}. Status: ${response.status}`);
  } catch (error: unknown) {
    if (axios.isAxiosError(error)) {
      // Log detailed error information from Axios
      console.error(`Mailchimp sync error for ${userData.email}: ${error.response?.status} - ${error.response?.statusText}`);
    } else {
      // General error logging
      console.error('Unknown error occurred during Mailchimp sync:', error);
    }
    throw new Error(`Failed to sync user ${userData.email} with Mailchimp`);
  }
}

async function updateUserAndSync(userId: string, updatedData: UserData): Promise<void> {
  try {
    // Update the user in Strapi
    const user = await strapi.services.user.update({ id: userId }, updatedData);
    
    // Sync the updated user data with Mailchimp
    await syncToMailchimp(user);
    
    // Log success (Optional)
    console.log(`User ${userId} updated and synced with Mailchimp`);
  } catch (error) {
    console.error(`Error updating user ${userId} and syncing with Mailchimp:`, error);
    throw error; // Rethrow the error to be handled by the calling function
  }
}
import Discord from 'discord.js';

// Discord client initialization
const client = new Discord.Client();

(async () => {
  try {
    // Ensure the bot token exists before logging in
    if (!process.env.DISCORD_BOT_TOKEN) {
      throw new Error('DISCORD_BOT_TOKEN is not defined in environment variables');
    }

    await client.login(process.env.DISCORD_BOT_TOKEN);
    console.log('Bot successfully logged in.');
  } catch (error: any) {
    console.error('Failed to log in to Discord:', error.message);
    process.exit(1); // Exit the process if the bot fails to log in
  }
})();

// Function to assign a role to a user
export async function assignRoleToUser(discordUserId: string, roleName: string): Promise<void> {
  try {
    // Ensure the guild ID is set
    const guildId = process.env.DISCORD_GUILD_ID;
    if (!guildId) {
      throw new Error('DISCORD_GUILD_ID is not defined in environment variables');
    }

    const guild = await client.guilds.fetch(guildId);
    console.log(`Fetched guild: ${guild.name}`);

    const member = await guild.members.fetch(discordUserId);
    console.log(`Fetched user: ${member.user.tag}`);

    const role = guild.roles.cache.find(role => role.name === roleName);

    if (role) {
      await member.roles.add(role);
      console.log(`Role "${roleName}" successfully assigned to user: ${member.user.tag}`);
    } else {
      console.error(`Role "${roleName}" not found in the guild`);
    }
  } catch (error: any) {
    // Detailed error logging with context
    console.error(`Error assigning role "${roleName}" to user ${discordUserId}:`, error.message);
  }
}
import axios, { AxiosResponse, AxiosError } from 'axios';

interface DiscountResponse {
  code: string;
  expiry: string;
}

// Function to issue a discount code to a user
async function issueDiscountCode(userEmail: string): Promise<DiscountResponse> {
  // Validate the environment variable for Kitbash3D API
  const apiUrl = process.env.KITBASH3D_API_URL;
  
  if (!apiUrl) {
    throw new Error('KITBASH3D_API_URL is not defined in environment variables');
  }

  try {
    const response: AxiosResponse<DiscountResponse> = await axios.post(`${apiUrl}/generate-discount`, {
      email: userEmail,
      discount: '20%',
    });

    console.log('Discount code issued:', response.data);
    return response.data;
  } catch (error: unknown) {
    if (axios.isAxiosError(error)) {
      console.error(`Failed to issue discount code for ${userEmail}: ${error.response?.status} - ${error.response?.statusText}`);
    } else {
      console.error('Unknown error occurred:', error);
    }
    throw new Error('Discount code generation failed');
  }
}

// Function to create course enrollment and issue discount code
export async function createCourseEnrollment(userEmail: string, premiumCourseId: number): Promise<void> {
  try {
    // Enroll the user in the premium course
    await strapi.query('course-enrollment').create({
      data: { user: userEmail, course: premiumCourseId }
    });

    console.log(`User ${userEmail} successfully enrolled in course ID ${premiumCourseId}`);

    // Issue a discount code after successful enrollment
    await issueDiscountCode(userEmail);
  } catch (error: unknown) {
    if (error instanceof Error) {
      console.error(`Error during course enrollment or discount issuance for ${userEmail}: ${error.message}`);
    } else {
      console.error('Unknown error occurred:', error);
    }
    throw new Error('Enrollment or discount code issue failed');
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants