GithubHelp home page GithubHelp logo

laudspeaker / laudspeaker Goto Github PK

View Code? Open in Web Editor NEW
1.4K 18.0 109.0 30.4 MB

๐Ÿ“ข Laudspeaker is an Open Source Customer Engagement and Product Onboarding Platform. Open Source alternative to Braze / One Signal / Customer Io / Appcues / Pendo . Use Laudspeaker to design product onboarding flows and send product and event triggered emails, sms, push and more.

Home Page: https://laudspeaker.com/?ref=github

License: Other

JavaScript 5.85% TypeScript 93.43% HTML 0.02% CSS 0.55% Shell 0.08% Dockerfile 0.08%
customer-engagement nestjs react typescript nodejs email-marketing sms-marketing omnichannel customer-journey push-notifications

laudspeaker's Introduction

Join Slack Community Follow Laudspeaker Commits

Laudspeaker - Open Source Customer Engagement and Product Onboarding and Adoption Platform. Alternative to Braze / One Signal / Customer io / Appcues / Pendo

UI2
  • Visual Journey Builder: Build complex workflows the whole team can understand in a visual tool. Describe the onboarding journey and messaging steps clearly.
  • Multiple out of product messaging channels like email and sms: Trigger Emails, SMS and more to nudge users back to complete specific flows.
  • Monitor and Track User Progress: See user progress and which steps users get stuck on.
  • Personalize Journeys for Different User Personas: Build different user journeys for different personas, so that you highlight the right features for the right users.
  • Edit, Experiment and Change Onboarding Easily: Make changes to onboarding copy easily, or edit live journeys.

๐Ÿš€ Get Started

Use Laudspeaker Cloud or if you are interested in our paid self deployed (business/enterprise) plan book a time below:

Want to use at your company?

Questions? Please join our Slack channel or visit our site.

๐Ÿ”ฅ What makes Laudspeaker cool?

Lauspeaker is the only multi-channel open-source customer messaging workflow software, which is focused on being event triggered, has been built with a visual journey feature from day one and is focused on scalability.

We support email, sms and slack as a channel and have many more channels on our roadmap.

We are planning to build Laudspeaker to work well with the Modern Data Stack, integrating with data warehouses and other services so you can easily import and export data with no fear of lock in or losing control of your data.

๐Ÿฅ Status

  • Public Alpha: Anyone can sign up over at laudspeaker.com but go easy on us, there are wrinkles and we're just getting started.
  • Public Beta: Stable enough for most non-enterprise use-cases.
  • Public: Production-ready.

We're currently in Public Alpha.

License

Laudspeaker is open source and released under the AGPL-3.0 license with the exception of our ee directory (which is currently empty!) but will be under the Laudspeaker Enterprise Edition license.

๐ŸŒฑ Contribute

We would love to see you contribute to Laudspeaker. Join our slack to get involved.

Follow Us

laudspeaker's People

Contributors

abheek9 avatar claude avatar dennissnijder avatar gitstart-app[bot] avatar gitstart-laudspeaker avatar jaredhanson11 avatar mattyait avatar mbergwall2222 avatar mcharawi avatar moustafaeid avatar mykolalaudspeaker31 avatar rsverma007 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

laudspeaker's Issues

SSL Cert expired on laudspeaker.com

Bug description

The SSL certificate for laudspeaker.com has expired yesterday.

How to reproduce

  1. Navigate to laudspeaker.com
  2. Error

Thank you for your bug report โ€“ we love squashing them!

Improving ideas

I took a look at your project more deeply and found some issues that could be improved for better performance, code quality and time for developing

A modular approach architecture

First thing first we should add a module folder in server/src. And create more modules for better code organization and ease of re-use. For example you have a lot of logic like this:

this.installer = new InstallProvider({
      clientId: process.env.SLACK_CLIENT_ID,
      clientSecret: process.env.SLACK_CLIENT_SECRET,
      legacyStateVerification: true,
      stateStore: {
        // generateStateParam's first argument is the entire InstallUrlOptions object which was passed into generateInstallUrl method
        // the second argument is a date object
        // the method is expected to return a string representing the state
        generateStateParam: async (
          installUrlOptions: InstallURLOptions,
          date: Date
        ) => {
          // generate a random string to use as state in the URL
          const state = new State();
          state.installUrlOptions = installUrlOptions;
          state.now = date;
          // save installOptions to cache/db
          let ret;
          try {
            ret = await this.stateRepository.save(state);
          } catch (e) {
            this.logger.error('Error: ' + e);
            ret = { id: null };
          }
          // return a state string that references saved options in DB
          return ret.id;
        },
        // verifyStateParam's first argument is a date object and the second argument is a string representing the state
        // verifyStateParam is expected to return an object representing installUrlOptions
        verifyStateParam: async (date: Date, state: string) => {
          // fetch saved installOptions from DB using state reference
          let decoded;
          try {
            decoded = await this.stateRepository.findOneBy({ id: state });
          } catch (e) {
            this.logger.error('Error: ' + e);
          }
          const generatedAt = new Date(decoded.now);
          const passedSeconds = Math.floor(
            (date.getTime() - generatedAt.getTime()) / 1000
          );
          if (passedSeconds > 600) {
            throw new InvalidStateError('The state value is already expired');
          }
          return decoded.installUrlOptions;
        },
      },

which you should separate into modules and just use them in different places. Also I found that your file structure is complicated, I don't understand why you decided to use modules, controllers and services all together in 1 folder. It's easier to navigate between structure when you know where to find them, like the tests, you have a test folder but all of your tests in api folder with all of the logic which should be separated.

Redux Toolkit

To match Redux work done by hands use redux toolkit instead. Reasons why I would prefer Toolkit instead of default Redux:

  • A lot lesser boilerplate code is required compared to Redux.
  • You don't need to do manual thunk setup as redux-toolkit comes with out of the box createAsyncThunk which enables you to perform async operations in very hastle free way.
  • getState is also very helpful in obtaining state variables across any of your actions or async operations.
  • Mutability might be considered as advantage or disadvantage, but if you're not too used to writing with spread operators, you might love this feature as well. Do straight assignments and let redux toolkit take care of mutability under the hoods.
  • current can be used to log your state anywhere in case you want to debug and understand where things are going wrong. (Ofcourse, Redux debugger tools are great as well)
import { createSlice } from '@reduxjs/toolkit';

export const todoSlice = createSlice({
  name: 'todos',
  initialState: [],
  reducers: {
    addTodo: (state, action) => {
      const todo = {
        id: uuid(),
        text: action.payload,
      };

      state.push(todo);
  },
});

// this is for dispatch
export const { addTodo } = todoSlice.actions;

// this is for configureStore
export default todoSlice.reducer;

Generics & Any types

const conditionalCompare = (custAttr: any, checkVal: any, operator: string) => {
  switch (operator) {
    case 'isEqual':
      return custAttr == checkVal;
    case 'isNotEqual':
      return custAttr != checkVal;
    case 'contains':
      return custAttr.includes(checkVal);
    case 'doesNotContain':
      return !custAttr.includes(checkVal);
    case 'isBoolEqual':
      return custAttr === (checkVal === 'true');
    case 'isBoolNotEqual':
      return custAttr !== (checkVal === 'true');
    case 'isTimestampBefore':
      return new Date(custAttr) < new Date(checkVal);
    case 'isTimestampAfter':
      return new Date(custAttr) > new Date(checkVal);
    case 'isGreaterThan':
      return custAttr > Number(checkVal);
    case 'isLessThan':
      return custAttr < Number(checkVal);
  }
};

As I see in your code base you are using any type which we should avoid. As I told you here we could use some eslint rules for avoiding this problem. Using any removes all type checking provided by TypeScript, which is one major reason for using TypeScript over JavaScript. By using any, you expose yourself to issues that are difficult to trace and debug, especially once the code is deployed in production. And also we should use generics to make our functions reusable. As I saw in your code in most cases you are using type any because you could receive different types properties that's one of the reasons why we should use generics instead.

Thank you for your feature request โ€“ we love each and every one!

Allow users to use a single design template with snippets for each step of a journey

Is your feature request related to a problem?

Yes

Please describe.

If I need to make changes to the design of my template. I don't want to have to update each template for each step. It would be easier if there was a single design template for a journey that I could update once.

Describe the solution you'd like

For each journey, I specify the design template to use. Then for each step, I can put in the custom HTML / text that needs to be inserted for that step.

Describe alternatives you've considered

Right now, I've created a similar system locally using MJML but it would better if LaudSpeaker was the source of truth.

Additional context

Thank you for your feature request โ€“ we love each and every one!

Improvement ideas

Brocken Data Flow

There are alot of inconsistent operations throught out the application:

  async insert(
    account: Account,
    createAudienceDto: CreateAudienceDto
  ): Promise<Audience> {
    const audience = new Audience();
    audience.name = createAudienceDto.name;
    audience.customers = [];
    audience.templates = [];
    audience.isDynamic = createAudienceDto.isPrimary
      ? createAudienceDto.isDynamic
      : false;
    audience.isPrimary = createAudienceDto.isPrimary;
    audience.inclusionCriteria = createAudienceDto.isPrimary
      ? createAudienceDto.inclusionCriteria
      : undefined;
    audience.description = createAudienceDto.description;
    audience.ownerId = account.id;
    try {
      const resp = await this.audiencesRepository.save(audience);
      const stats = this.statsRepository.create({ audience: resp });
      await this.statsRepository.save(stats);
      return resp;
    } catch (e) {
      console.error(e);
    }
  }
const newAudiences = await Promise.all(
      oldWorkflow.audiences?.map(async (id) => {
        const { name, description, inclusionCriteria, isDynamic, isPrimary } =
          await this.audiencesService.findOne(user, id);
        const newAudience = await this.audiencesService.insert(user, {
          name,
          description,
          inclusionCriteria,
          isDynamic,
          isPrimary,
        });
        return newAudience.id;
      }) || []
    );

With this approach whole data flow brokes after one unsuccesful operation.
There are two possible solutions to this problem:

  1. Rewrite all operations as transactions(as than each operation will eather complete or not complete, regardless to others)
    
  2. Transition to event driven architecture(as then you can save dead operations and execute them later using message brocker)
    

Second approach is preferable as it is more failsafe

Patterns

There are a lot of places which could be improved with strategy patterns.

For example:
https://github.com/laudspeaker/laudspeaker/blob/main/packages/server/src/api/templates/templates.service.ts - Can be simplified by strategy pattern

Async Logic on Frontend

Rework data fetching system with Redux thunk/saga, all data should be cached and stored in redux store. Do not use plane calls of http. It can potentially provoke a lot of bugs during the final testing.

Local installation - can't create an account - unexpected error

Bug description

Hi, I really would like to test Laudspeaker locally! I followed all the steps outlined in the documentation.
However, I'm stumbling upon a challenge, it seems I can't register an account locally because of some unexpected error. Am I missing some installation step? Please see the screenshots below:
Schermยญafbeelding 2023-10-17 om 12 42 21

image

How to reproduce

  1. Pulled the latest version.
  2. created .env files with 'mv env-server-example packages/server/.env' and 'mv env-client-example packages/client/.env'
  3. Insantiated Mongo
  4. Run backend and frontend by 'npm install' & 'npm run start'

Environment

  • self-hosted Laudspeaker v1.6.0

A few words about the organization of data in the database

Foreword:

In the first sections, I tried to describe the course of my thoughts about the first impression of the product and the project as a whole.

My thought and idea when researching a project always starts with reading the documentation and other attached materials. The essence of this for me is to understand what problem the product solves. And also to get acquainted with the integrity of the project. What are the relationships between functionality, features and other parts of the application. From the first step I try to understand what the project looks like functionally. Your documentation and videos did not help with this step. But right on the video, I spent a lot of time as I watched it with a large number of pauses and rewinds. Because I wanted to understand the essence of the application.

The second step I always have is the study of the database. To make sure in the course of thought of the developer. It helps me better understand the relationships between data and entities. I immediately imagine in my head a diagram of relationships between tables and other things. It is important for me to understand the direction of thought when developing a project. To better understand the goals and plans of the product.

After I studied the entity schemas of almost every module. I decided to make a simple table of connections, since I couldnโ€™t immediately imagine this in my head. It looked a little confusing to me. And I wanted to simplify it in order to better perceive what is happening there.
I initially also studied the main methods of controllers in modules in order to also understand a little better the overall capabilities of the project and actions. I didnโ€™t use any of the services.

I drew up a diagram of the relationships between data tables as I saw it at first glance.
https://drive.google.com/file/d/1eGZZKlfPwcy737dQLZG-bOMiOVJiDNfF/view?usp=sharing

And it became easier for me to perceive connections. But Iโ€™ve also started to see some things that Iโ€™m missing. These are relationships between parameters, such as ownerId, templates, customers, audiences, as well as all parameters related to slack integration (more on this in another sentence.

My first suggestion:

This is to add one-to-one and one-to-many relationships. For typeorm, this will immediately improve the data connection with the help of the relations option, we can immediately select related data.

Second suggestion:

This is to make the slack module more independent. And also reduce all references to this service to one separate entity. Also describe the methods associated with it in the slack module service. This makes it easier to use this integration. It will also remove unnecessary confusion with the features used.

Complex Journey test 1

Creating a complex journey with multisplit attribute, multisplit event, experiment and webhooks

Context:

We have a large number of journey features now, and need to make sure they are working as intended. One way end to end tests can help us is with an adapted real life journey.

To Do list:

  • in the test after signing up, upload a csv using the test helper function previously used, and using this csv:
    correctness_testing.csv

  • Create a new test helper function called simulatedEvents that fires a few events to the events endpoint, if this is done correctly you will see the results in the event tracker:

Screenshot 2024-02-27 at 12 16 04โ€ฏAM You will need to use the accounts api key found here: Screenshot 2024-02-27 at 12 19 42โ€ฏAM the request will look something like but with a different url, api, key and event name/payload:
var request = require('request');
var options = {
  'method': 'POST',
  'url': 'https://api.laudspeaker.com/events/',
  'headers': {
    'Authorization': 'Api-Key 9mm0MUF6f5du4jTry9nK7kCreJ6t2Y1fZvtezS04',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    "correlationKey": "user_id",
    "correlationValue": "[example_user_id]",
    "source": "custom",
    "event": "your_event",
    "payload": {
      "example": 4
    }
  })

};
request(options, function (error, response) {
  if (error) throw new Error(error);
  console.log(response.body);
});

  • the events fired should correspond to some users from the csv that was uploaded
  • Please create a cypress test that recreates this journey from scratch, use webhooks instead of push. The message content doesnt matter, but pay attention to the multisplit conditions, if the csv doesnt have a property shown in the loom, use a property that is in the csv but has the same type as shown in the video ie replace boolean with boolean.

Live Journey Overview

Live Journey Overview Tab

##Context,
Right now for our live journeys, we do not have an overview tab, where our users can see a snapshot of how the journey is doing. We want to add a tab called 'Overview' as the first tab of live journeys. (For reference this a how you get to a live journey)

Here are the design files

You can assume you are getting the data you need from specific API calls, and for the conversion rate box, you can use mock data for now. For the definitions of the conversion events, shown on hover, you should assume you get that from an api call when you load the page, for now use mock data.

Segment Correctness tests

We want to add end to end integration tests for our segment features

##Context,
we currently use cypress to write tests, we need to add automated testing suites for a number of our features, that we have been doing mostly manually up till now.

You can see some of our existing tests in the tests package

You can run tests by using the npm run test:run --num=XXX command, where XXX is a number of a test

an example test that works is 040.

you can use the cypress extension to help you generate code like this too if its helpful (may or may not be)

##To Do list
Could you complete test 020

  • we need to sign up and set up the organization
  • complete the uploadCSV test helper
  • use uploadCSV to upload the correctness_testing.csv
  • create a segment for each attribute type, and comparison pair: (string, number, date, boolean) X (equal, not equal, etc.)
  • Make sure the segments you create only have one user, and navigate to that user's page to check they are part of that segment

This is the segment file to be used:
correctness_testing.csv

##Story size

##Dates

##Tags

##More Resources

What is the difference between Workflow and Journey?

Hi, thanks for this amazing efforts โ™ฅ

I have some questions about the implementation of the system:

  • I noticed that there're similar two modules (Workflow and Journey), while Journey module is used in most places, but there's some places where Workflow module is used?

  • If I'm right, Workflow module is an old version of Journey, if that is true, why there's new updates and commits to workflow logic?

That's all my questions,

Thanks.

firebase push notification

Is your feature request related to a problem?

we don't yet support push notifications, matthew requested starting with firebase push

Describe the solution you'd like

Describe alternatives you've considered

Additional context

Thank you for your feature request โ€“ we love each and every one!

Support for AWS SES provider

Is your feature request related to a problem?

Not a problem, but would love the have the option to send my mail using AWS SES.

Describe the solution you'd like

A new mail provider in the UI for AWS SES (https://aws.amazon.com/ses/) should require me to provide an access ID & Secret.

Describe alternatives you've considered

An alternative would be to use SMTP to send through AWS SES, however the SMTP option seems to be locked for now (not been implemented yet?)

in app modals and content cards

Is your feature request related to a problem?

two customers have asked for modals, that are triggered by user events that show programmatic content. One customer has asked for modals, another for modals and content cards

Describe the solution you'd like

Describe alternatives you've considered

Additional context

Thank you for your feature request โ€“ we love each and every one!

oath feature request

Is your feature request related to a problem?

brandon has mentioned the need for oath

Describe the solution you'd like

Describe alternatives you've considered

Additional context

Thank you for your feature request โ€“ we love each and every one!

SSO - Single sign (Github, Gitlab, etc)

Helpful title: I saw a -coming soon-, is this already on the works? Didn't find any issue about it.

image

##Context,
Link to PRD and short 3 sentences max

##To Do list
Make SSO work with :

  • Github
  • Google
  • Gitlab

##Story size

##Dates

##Tags

##More Resources

Unable to Login into the Public cloud Platformat

Bug description

Please describe.
If this affects the front-end, screenshots would be of great help.

How to reproduce

  1. Login into any cloud platform, The auth is going pending

Environment

  • [*
    Uploading Capture.JPGโ€ฆ
    ] Laudspeaker Cloud
  • self-hosted Laudspeaker, version/commit: please provide

Additional context

Thank you for your bug report โ€“ we love squashing them!

One Click Render Deploy Failing

Bug description

Followed all the instructions for One Click deploy on Render.
All services deployed up and running except Laudspeaker webservice.

It says following error -
error: required option '--host ' not specified

Attached screenshot.
Screenshot 2023-06-29 at 12 55 23

Am I doing something wrong?

refreshToken endpoint returning 404

Bug description

Please describe.
If this affects the front-end, screenshots would be of great help.

image

How to reproduce

1.Wait until access_token is invalid
2.try to fetch some data
3.

Environment

  • Laudspeaker Cloud
  • self-hosted Laudspeaker, version/commit: please provide

Additional context

In api.ts file line number 5


refreshtoken: "/api/refreshtoken"


This need to be updated to /api/refresh as the endpoint is refresh.

If possible I would love to contribute.

Thank you for your bug report โ€“ we love squashing them!

trigger to step loops

Is your feature request related to a problem?

Mathew mentioned that he would like to have a trigger from a step, loop back to the step. This makes sense, as it makes our journey's much more powerful

Describe the solution you'd like

Describe alternatives you've considered

Additional context

Thank you for your feature request โ€“ we love each and every one!

Slack link on homepage is broken

Bug description

Please describe.
If this affects the front-end, screenshots would be of great help.

How to reproduce

  1. Go to homepage
  2. Tap join community
  3. Broken

Environment

  • Laudspeaker Cloud
  • self-hosted Laudspeaker, version/commit: please provide

Additional context

image

Thank you for your bug report โ€“ we love squashing them!

Update Webhook Builder

Updating the Webhook template builder

Context,

Currently our Webhook template builder is a vestige of our old design system. We need to update it, and want to show a nice simulation of what it would look like on mobile.

Page in question is found by going to https://app.laudspeaker.com/templates, then click create, select webhook

Screenshot 2024-02-16 at 1 57 06โ€ฏAM

This is the design file for the output we expect: https://www.figma.com/file/qdiH1cLgyRmxps8i3ud6rQ/%5BEXT%5D-Webhook?type=design&node-id=0%3A1&mode=design&t=UD6RfLgkcU2AeOth-1

You can reuse components. The new design should replicate all the same backend calls the original design is making, so make sure to test. Pay special attention to the Raw content view on the left hand side, that should update as user makes different selections, and adds input like in the old design here: https://www.loom.com/share/1796beb338ab42e7a91b1f52977d32fb?sid=965dd1ce-9618-4ae8-90ba-f63254a9887a

You should be able to test this template, and should show the results of the constructed http request in test results modal

After the template is saved, it should appear in the templates page:

Screenshot 2024-02-16 at 1 51 03โ€ฏAM

and if a user clicks duplicate, or deletes, both of those functions should work correctly as well

Screenshot 2024-02-16 at 1 51 47โ€ฏAM

copy and paste in the journey builder

Is your feature request related to a problem?

For complex journeys, we need to create step by step, this can take a very long time

Describe the solution you'd like

it would be nice to be able to select multiple steps and copy or cut and paste

Describe alternatives you've considered

Thank you for your feature request โ€“ we love each and every one!

Frequency Capping

Frequency Capping:

##Context,
We need to add the ability to set rules for how many messages, of different types a user can receive irrespective of how many journeys they are signed up for. This is called frequency capping and will be a setting tab in our workspace settings.

You can see the designs here

For the modal, an example page in a similar style is found at staging-app.laudspeaker.com/flow

Screenshot 2024-02-23 at 2 28 17โ€ฏAM

To get the data for the modal you can assume you make a call like : const { data } = await ApiService.get(SOME STUFF HERE) you can assume we return the data in a similar format to what we reuturn for /flow

We also need to add a toggle to the journey settings page, and under that toggle is a button for the frequency rules, if a user clicks that a new tab in the browser should open with the frequncy rules. You will need to update the journey settings object so when a journey is saved this information is saved in our database. You can update in /FlowBuilderSettings.tsx and/or /flow-builder.reducer.ts . You may need to change the interface:

export interface JourneySettings {
  tags: string[];
  quietHours: JourneySettingsQuietHours;
  maxEntries: JourneySettingsMaxUserEntries;
  maxMessageSends: JourneySettingsMaxMessageSends;
}

mixpanel integration

Is your feature request related to a problem?

martin has asked for a mixpanel integration

Describe the solution you'd like

  • we have gotten in contact with mixpanel and are looking at the best solution forward, one option is using their event download api , another is their cohorts api

Describe alternatives you've considered

Additional context

Thank you for your feature request โ€“ we love each and every one!

How could I create a new Communication Provider?

Is your feature request related to a problem?

I have a API for WhatsApp and I would like to create a provider to use laudspeaker. Is there a Doc to create a custom provider?

Please describe.

Describe the solution you'd like

Describe alternatives you've considered

Additional context

Thank you for your feature request โ€“ we love each and every one!

Suggestions about improving the code base.

Redux

First think i want to mention is redux. I am a big fan of it. But nowadays there many different and more light substitutions that are present.
So first thing that comes as an alternative are custom hooks to be used to fetch, mutate, and manipulate with data. Basic example of such thing in auth flow.

export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
  const swrKey = {
    from: 'profile_info',
    select: [
      'id',
      'user',
      'userRole:user_role'
    ],
  }

// Doesnt matter which exactly fetcher is being used
  const {
    data: profile,
    error: globalError,
    isLoading,
    isValidating,
  } = useSWR<Profile, ApiError>(swrKey, databaseSelector)

 return <Context.Provider value={value}>{children}</Context.Provider>
}

So, this is a very simple context hook which gives you an opportunity to easily manage the way data is stored, and actually is very easy to be scaled.

It also applies to the managing the styles.

It also applies to the services you have. As for now, i have not seen anything difficult or huge .But then as far as time goes, it will be increased in it's size, and may become difficult to refactor, So i would personally recommend to write some kind of hook that works with the database, and has usual methods which simulate everyday life cycle of communicating with backend(such straight things as fetching, mutating...)

Going next.

Documentation

A very nice thing is to actually see what you have done. So here comes as an approach to track the progress such libraries as React Sketch. app, React Storybook, Bit, Pattern Lab. So basically, is a documentation that you fill up with your components to see different options that are available within them. It helps to have a better understanding of your project.

Also about it. i have looked into many files and noticed that not so much of them have the comments and at least described props, which can be really handsome, whenever many developers are working in a team.

Going next.

SVG files

Also i would recommend to actually change the way you are storing the SVG files. It is very easy to be converted to jsx/tsx files, and they it would be able to receive props, etc..

Thank you for your feature request โ€“ we love each and every one!

push notifications in the editor

Is your feature request related to a problem?

Kishin asked for push notification designs in our template editor

Describe the solution you'd like

Describe alternatives you've considered

Additional context

Thank you for your feature request โ€“ we love each and every one!

Stopped journey shows "Edit" options under actions.

Bug description

Currently, stopped journeys aren't editable. Yet, they display an icon and link to "Edit" the journey.
Screen Shot 2023-04-02 at 2 27 04 AM

How to reproduce

  1. Create and run a journey.
  2. Stop the journey.
  3. Visit journey dashbaord and see that the "Edit" action is still there

Environment

  • Laudspeaker Cloud
  • self-hosted Laudspeaker, version/commit: please provide

Additional context

Solution:

  • Potentially change the "Edit" icon to perhaps something more generic, like three dots?

Screen Shot 2023-04-02 at 2 29 22 AM

  • Definitely change the "Edit" option in dropdown to "Show" or "View"

Will work on a PR to fix :)

Add support for multiple projects within an account.

Is your feature request related to a problem?

The issue i'm trying to resolve is wanting the ability to separate dev, stage and production environments. Some platforms introduce environments others just call them projects.

Describe the solution you'd like

Within one account, i'd like to have the ability to create multiple projects, each with their own api key, and the data/configuration would be isolated to each project.

Describe alternatives you've considered

creating multiple accounts, which is fine.

duplicate persons on posthog sync

Bug description

Please describe.
Our user Matthew hit the sync button on the posthog events page in settings

  • saw multiple users with same posthog id

How to reproduce

Environment

  • Laudspeaker Cloud - v0.1.0
  • self-hosted Laudspeaker, version/commit: please provide

Additional context

Thank you for your bug report โ€“ we love squashing them!

smtp email integration

Is your feature request related to a problem?

brandon has requested an smtp integration

Describe the solution you'd like

mahamad and brandon are working on it together

Describe alternatives you've considered

Additional context

Thank you for your feature request โ€“ we love each and every one!

Update SMS template builder

Updating the SMS template builder

##Context,
Currently our SMS template builder is a vestige of our old design system. We need to update it, and want to show a nice simulation of what it would look like on mobile.

Page in question is found by going to https://app.laudspeaker.com/templates, then click create, select sms

Screenshot 2024-02-16 at 1 36 41โ€ฏAM

This is the design file for the output we expect: https://www.figma.com/file/NbvFGmOZTJmfT5ToqXy78g/%5BExternal%5D-SMS-Inconsistency?type=design&node-id=0%3A1&mode=design&t=BqQO2rXLBUMWxWHi-1

you can reuse components from other template pages we have like the push builder. Pay special attention to the max size of messages, and make sure we can still add liquid tags for messaging personalization in this builder with {{}} (https://shopify.dev/docs/api/liquid/tags) which we can do in email and push for example.

This ticket is also for primarily the front end, you want to make sure the next, and save buttons work and make the right backend calls. But you dont need to implement the call from "send test" button

After the template is saved, it should appear in the templates page:

Screenshot 2024-02-16 at 1 51 03โ€ฏAM

and if a user clicks duplicate, or deletes, both of those functions should work correctly as well

Screenshot 2024-02-16 at 1 51 47โ€ฏAM

Experiance feedback + Template Builder alternative suggestion - Slate.js/Plate.js base or similar?

Hi Laudspeaker team, very impressed with your work! and would like to share my first experience.

  1. Was very confused why Laudspeaker needs to use 4 database engines - Redis, Mongo, Clickhouse and Postgres. Not a big issue ;)

  2. Couldnt run localhost demo to play with code without POSTHOG_KEY. Had to rename few enviroment options to run without docker compose.

  3. Journey Builder is very cool. Was confused about Drag&Drop functionality a bit at the beginning. React flow based UI, state machine (not DAG) looks very very right to me.

  4. Message Channel options. Very curious about roadmap here. Make it right without using 3rd party APIs would be a challenge.

  5. Template Builder.

Dont want to discourage here. Looks unusable to me. Cant imagine how non-technical person like Recruiters or SDR (Sales Development Representative) can use it.

For me, it would be faster to copy html and edit it somewhere else, rather when using a built-in editor.

Couldn't figure out how to use Template Variables. Thought initially it might related to API Calls functionality ...

How about building something more user friendly based on Slate.js/Plate.js editors?

Slate store editor data in JSON format which later can be converted into MJML or html directly. The overall user experience can be similar to editing Notion pages.

https://mjml.io/

Recommend to have a look at Attio CRM. Discovered it recently
https://attio.com/help/reference/email-and-calendar/send-emails-in-attio#using-variables

image image

Hope the above might help. I built CRM for recruitment business and your work is very inspiring to me. My end users run manual marketing and multistep candidate focused outbound sequences. Using Outreach or similar service was always overkill for us. Integrating with Laudspeaker might be the right move in the future.

Comprehensive Multisplit

Comprehensively Testing Multisplit

Context:

We have a large number of journey features now, and need to make sure they are working as intended. One way end to end tests can help us is with an adapted real life journey. In this test, we will exhaustively test a multi split in a journey with 5 branches each on a different user attribute type.

To Do list:

  • in the test after signing up, upload a csv using the test helper function previously used, and using this csv:
    correctness_testing.csv

  • use simulatedEvents to fire 5 events to the events endpoint, if this is done correctly you will see the results in the event tracker:

Screenshot 2024-02-27 at 12 16 04โ€ฏAM You will need to use the accounts api key found here: Screenshot 2024-02-27 at 12 19 42โ€ฏAM the request will look something like but with a different url, api, key and event name/payload:
var request = require('request');
var options = {
  'method': 'POST',
  'url': 'https://api.laudspeaker.com/events/',
  'headers': {
    'Authorization': 'Api-Key 9mm0MUF6f5du4jTry9nK7kCreJ6t2Y1fZvtezS04',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    "correlationKey": "user_id",
    "correlationValue": "[example_user_id]",
    "source": "custom",
    "event": "your_event",
    "payload": {
      "example": 4
    }
  })

};
request(options, function (error, response) {
  if (error) throw new Error(error);
  console.log(response.body);
});

  • the events fired should correspond to 5 users from the csv that was uploaded
  • Please create a cypress test that recreates this journey from scratch

One Click deploy on Render fail -

I setup new account. on render.com, added credit card as render said render.yaml required creditcard.
gave it a name, "docker deploy" was preselected in dropdown.

ERROR:
_A render.yaml file was found, but there was an issue.

web."laudspeaker".envVarGroups
env var group linkage depends on non-existent group: laudspeaker_

Have a way to filter out anonymous users from posthog after importing users

Is your feature request related to a problem?

Yang on our slack group, found it hard to find users who had signed up after importing users from posthog.

Describe the solution you'd like

He would like to be able to filter on people with a specific attribute

Describe alternatives you've considered

Thank you for your feature request โ€“ we love each and every one!

Suggestions about improving the code base.

Describe the solution you'd like

First think i want to mention is redux. I am a big fan of it. But nowadays there many different and more light substitutions are present.
So first think as an alternative comes as custom hooks to be used to fetch, mutate, and manipulate with data. Basic example of such is auth hook.
`export const AuthProvider: React.FC = ({ children }) => {
const [currentSession, setCurrentSession] = React.useState<Session | null>()

const swrKey: SupabaseSelector = {
from: 'profile_info',
select: [
'id',

],
type: 'single',

}

const {
data: profile,
error: globalError,
isLoading,
isValidating,
} = useSWR<Profile, ApiError>(currentSession ? swrKey : null, supabaseSelector)```
`


## Describe alternatives you've considered



## Additional context



#### *Thank you* for your feature request โ€“ we love each and every one!

Segments: Cannot read properties of undefined (reading 'id')

Bug description

Creating journeys before creating any segments yields the error Cannot read properties of undefined (reading 'id')
More stacktrace below

How to reproduce

  1. Clone the repo
  2. Run all services
  3. Sign up and go through the customer setup step
  4. Go to Audience -> People -> Settings and add email as primary key
  5. Create a journey with Start -> Wait until with Custom Event
  6. Publish journey

Environment

  • Laudspeaker Cloud
  • self-hosted Laudspeaker, version/commit: 86559cb
[2024-04-08 08:40:00.180 PM] [error] [Class: CronService] [Method: updateStatementsWithMessageEvents] [User: b1ba01c2-d7b6-448b-aff3-f929018f9c2d] [Session: 58b50aba-d152-40fe-b3c4-edc1c20f3d21]:   Cannot read properties of undefined (reading 'id') {stack: TypeError: Cannot read properties of undefined (reading 'id')
    at SegmentsService.getSegments (/src/api/segments/segments.service.ts:216:36)
    at CronService.updateStatementsWithMessageEvents (/src/app.cron.service.ts:788:53)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)   name: TypeError}
[2024-04-08 08:40:00.184 PM] [error] [Class: CronService] [Method: updateStatementsWithMessageEvents] [User: b1ba01c2-d7b6-448b-aff3-f929018f9c2d] [Session: 5632f302-f17d-4169-aa6e-7e537016d9bc]:   Cannot read properties of undefined (reading 'id') {stack: TypeError: Cannot read properties of undefined (reading 'id')
    at SegmentsService.getSegments (/src/api/segments/segments.service.ts:216:36)
    at CronService.updateStatementsWithMessageEvents (/src/app.cron.service.ts:788:53)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)   name: TypeError}
[2024-04-08 08:40:00.185 PM] [error] [Class: CronService] [Method: updateStatementsWithMessageEvents] [User: b1ba01c2-d7b6-448b-aff3-f929018f9c2d] [Session: 4e6bb94e-e6cf-4ca5-a9e3-ee7aa4eecdfe]:   Cannot read properties of undefined (reading 'id') {stack: TypeError: Cannot read properties of undefined (reading 'id')
    at SegmentsService.getSegments (/src/api/segments/segments.service.ts:216:36)
    at CronService.updateStatementsWithMessageEvents (/src/app.cron.service.ts:788:53)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)   name: TypeError}
[2024-04-08 08:40:00.190 PM] [debug] [Class: CronService] [Method: updateStatementsWithMessageEvents] [User: b1ba01c2-d7b6-448b-aff3-f929018f9c2d] [Session: 0d2b7b99-15a7-4dc3-a0c1-21546e52f807]:   error updating segment: undefined
[2024-04-08 08:40:00.195 PM] [debug] [Class: CronService] [Method: updateStatementsWithMessageEvents] [User: b1ba01c2-d7b6-448b-aff3-f929018f9c2d] [Session: 832d643a-be1a-4dad-a7bc-c9ae7415b0f5]:   error updating segment: undefined
[2024-04-08 08:40:00.196 PM] [error] [Class: CronService] [Method: updateStatementsWithMessageEvents] [User: b1ba01c2-d7b6-448b-aff3-f929018f9c2d] [Session: d43f4164-f240-4b72-a070-a990e441c69e]:   Cannot read properties of undefined (reading 'id') {stack: TypeError: Cannot read properties of undefined (reading 'id')
    at SegmentsService.getSegments (/src/api/segments/segments.service.ts:216:36)
    at CronService.updateStatementsWithMessageEvents (/src/app.cron.service.ts:788:53)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)   name: TypeError}
[2024-04-08 08:40:00.198 PM] [error] [Class: CronService] [Method: updateStatementsWithMessageEvents] [User: b1ba01c2-d7b6-448b-aff3-f929018f9c2d] [Session: 1dbd22f9-c61d-476d-b4f7-afec32c9f931]:   Cannot read properties of undefined (reading 'id') {stack: TypeError: Cannot read properties of undefined (reading 'id')
    at SegmentsService.getSegments (/src/api/segments/segments.service.ts:216:36)
    at CronService.updateStatementsWithMessageEvents (/src/app.cron.service.ts:788:53)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)   name: TypeError}
[2024-04-08 08:40:00.202 PM] [error] [Class: CronService] [Method: updateStatementsWithMessageEvents] [User: b1ba01c2-d7b6-448b-aff3-f929018f9c2d] [Session: 3b734d56-437d-4515-a515-a6d2330e52e6]:   Cannot read properties of undefined (reading 'id') {stack: TypeError: Cannot read properties of undefined (reading 'id')
    at SegmentsService.getSegments (/src/api/segments/segments.service.ts:216:36)
    at CronService.updateStatementsWithMessageEvents (/src/app.cron.service.ts:788:53)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)   name: TypeError}
[2024-04-08 08:40:00.205 PM] [error] [Class: CronService] [Method: updateStatementsWithMessageEvents] [User: b1ba01c2-d7b6-448b-aff3-f929018f9c2d] [Session: 17cf663a-eab7-448d-b1ec-83cee3b44b45]:   Cannot read properties of undefined (reading 'id') {stack: TypeError: Cannot read properties of undefined (reading 'id')
    at SegmentsService.getSegments (/src/api/segments/segments.service.ts:216:36)
    at CronService.updateStatementsWithMessageEvents (/src/app.cron.service.ts:788:53)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)   name: TypeError}
[2024-04-08 08:40:00.206 PM] [error] [Class: CronService] [Method: updateStatementsWithMessageEvents] [User: b1ba01c2-d7b6-448b-aff3-f929018f9c2d] [Session: 4712b198-ea4a-4b03-8718-77786fc72fca]:   Cannot read properties of undefined (reading 'id') {stack: TypeError: Cannot read properties of undefined (reading 'id')
    at SegmentsService.getSegments (/src/api/segments/segments.service.ts:216:36)
    at CronService.updateStatementsWithMessageEvents (/src/app.cron.service.ts:788:53)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)   name: TypeError}
[2024-04-08 08:40:00.208 PM] [error] [Class: CronService] [Method: updateStatementsWithMessageEvents] [User: b1ba01c2-d7b6-448b-aff3-f929018f9c2d] [Session: 96b4f2ee-98af-4792-bb1f-213ce47ed85f]:   Cannot read properties of undefined (reading 'id') {stack: TypeError: Cannot read properties of undefined (reading 'id')
    at SegmentsService.getSegments (/src/api/segments/segments.service.ts:216:36)
    at CronService.updateStatementsWithMessageEvents (/src/app.cron.service.ts:788:53)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)   name: TypeError}
[2024-04-08 08:40:00.209 PM] [error] [Class: CronService] [Method: updateStatementsWithMessageEvents] [User: b1ba01c2-d7b6-448b-aff3-f929018f9c2d] [Session: 38b13b62-fda5-444e-ad11-1329d2d14cd1]:   Cannot read properties of undefined (reading 'id') {stack: TypeError: Cannot read properties of undefined (reading 'id')
    at SegmentsService.getSegments (/src/api/segments/segments.service.ts:216:36)
    at CronService.updateStatementsWithMessageEvents (/src/app.cron.service.ts:788:53)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)   name: TypeError}
[2024-04-08 08:40:00.211 PM] [error] [Class: CronService] [Method: updateStatementsWithMessageEvents] [User: b1ba01c2-d7b6-448b-aff3-f929018f9c2d] [Session: 17befd9e-a287-4f21-b8ff-3551cfe9af50]:   Cannot read properties of undefined (reading 'id') {stack: TypeError: Cannot read properties of undefined (reading 'id')
    at SegmentsService.getSegments (/src/api/segments/segments.service.ts:216:36)
    at CronService.updateStatementsWithMessageEvents (/src/app.cron.service.ts:788:53)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)   name: TypeError}
[2024-04-08 08:40:00.218 PM] [error] [Class: CronService] [Method: updateStatementsWithMessageEvents] [User: b1ba01c2-d7b6-448b-aff3-f929018f9c2d] [Session: d7c9585c-1ed4-4a50-a51f-8f1f12918f0b]:   Cannot read properties of undefined (reading 'id') {stack: TypeError: Cannot read properties of undefined (reading 'id')
    at SegmentsService.getSegments (/src/api/segments/segments.service.ts:216:36)
    at CronService.updateStatementsWithMessageEvents (/src/app.cron.service.ts:788:53)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)   name: TypeError}
[2024-04-08 08:40:00.218 PM] [error] [Class: CronService] [Method: updateStatementsWithMessageEvents] [User: b1ba01c2-d7b6-448b-aff3-f929018f9c2d] [Session: 90155b04-9c05-41b8-be14-1c3a0d908aaa]:   Cannot read properties of undefined (reading 'id') {stack: TypeError: Cannot read properties of undefined (reading 'id')
    at SegmentsService.getSegments (/src/api/segments/segments.service.ts:216:36)
    at CronService.updateStatementsWithMessageEvents (/src/app.cron.service.ts:788:53)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)   name: TypeError}
[2024-04-08 08:40:00.224 PM] [error] [Class: CronService] [Method: updateStatementsWithMessageEvents] [User: b1ba01c2-d7b6-448b-aff3-f929018f9c2d] [Session: 6206ff7b-7735-4d40-8c8e-282afeacc68f]:   Cannot read properties of undefined (reading 'id') {stack: TypeError: Cannot read properties of undefined (reading 'id')
    at SegmentsService.getSegments (/src/api/segments/segments.service.ts:216:36)
    at CronService.updateStatementsWithMessageEvents (/src/app.cron.service.ts:788:53)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)   name: TypeError}
[2024-04-08 08:40:00.231 PM] [error] [Class: CronService] [Method: updateStatementsWithMessageEvents] [User: b1ba01c2-d7b6-448b-aff3-f929018f9c2d] [Session: 832d643a-be1a-4dad-a7bc-c9ae7415b0f5]:   Cannot read properties of undefined (reading 'id') {stack: TypeError: Cannot read properties of undefined (reading 'id')
    at SegmentsService.getSegments (/src/api/segments/segments.service.ts:216:36)
    at CronService.updateStatementsWithMessageEvents (/src/app.cron.service.ts:788:53)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)   name: TypeError}
[2024-04-08 08:40:00.233 PM] [error] [Class: CronService] [Method: updateStatementsWithMessageEvents] [User: b1ba01c2-d7b6-448b-aff3-f929018f9c2d] [Session: 0d2b7b99-15a7-4dc3-a0c1-21546e52f807]:   Cannot read properties of undefined (reading 'id') {stack: TypeError: Cannot read properties of undefined (reading 'id')
    at SegmentsService.getSegments (/src/api/segments/segments.service.ts:216:36)
    at CronService.updateStatementsWithMessageEvents (/src/app.cron.service.ts:788:53)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)   name: TypeError}

Thank you for your bug report โ€“ we love squashing them!

Can't add SendGrid account

Bug description

After correctly adding the Sendgrid API key and the email address I receive a 400 with the message: "There is something wrong with your sendgrid account. Check if your email is verified." I have tried with a key that has full access and one that has partial access to only sending emails. I also tried with the authenticated email configured in Sendgrid as well as with the email I use to login. We use that Sendgrid account in other SaaS solutions without a problem.

How to reproduce

  1. Go to settings
  2. Go to Email
  3. Select Sendgrid
  4. Enter the API Key
  5. Enter the Email
  6. Click Save

Environment

  • Laudspeaker Cloud
  • self-hosted Laudspeaker, version/commit: please provide

Additional context

I do get an email confirmation that says "If you see this message, you successfully connected your sendgrid email to laudspeaker"

ActivityPub Integration

Being able to use Laudspeaker to automate posting to activitypub (mastodon, pixelfed, PeerTube, etc) would bring this powerful sharing tool into the Fediverse

Improvement ideas

Is your feature request related to a problem?

Nope, everything is working as expected

Describe the solution you'd like

So, when I did take a look at your codebase, I found some improvements that could be done:

  1. Use custom hook for switching a theme. I see that you are using tailwind for that's purpose, and that's great! But you could make your codestyle cleaner if you would use custom hook.

  2. As far as I see, you are using airbnb eslint config. And it would be really great, if you would add some rules for it:

'no-constant-condition': 'error',
'no-unreachable': 'error',
'no-unused-expressions': 'error',

And also I've been using plugin unicorn, so from there you could use config like that, to optimize your filenames and namings (for better readability):

'unicorn/prevent-abbreviations': [
  'error',
    {
       replacements: {
         prop: false,
         props: false,
         ref: false,
         refs: false,
       },
    },
],
'unicorn/filename-case': [
  'error',
    {
       case: 'camelCase',
    },
],
  1. You could use lighthouse in your .github/workflows. This is cool action that analyzes web apps and web pages, collecting modern performance metrics and insights on developer best practices.
    LIGHTHOUSE_EXAMPLE

Thank you for your feature request โ€“ we love each and every one!

Emails in different Languages

Is your feature request related to a problem?

In order to address people in their language we want to define email templates in their language.

Describe the solution you'd like

Add a way to have email templates in multiple languages. Maybe add a way to translate text elements so that the email layout stays the same.

Describe alternatives you've considered

Duplicate the whole flow...

Thank you for your feature request โ€“ we love each and every one!

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.