Skip to content

Commit

Permalink
Merge pull request #425 from RBND-studio/dev
Browse files Browse the repository at this point in the history
Merge dev
  • Loading branch information
VojtechVidra committed Jun 25, 2024
2 parents 55a7509 + e78fe95 commit ac7f124
Show file tree
Hide file tree
Showing 28 changed files with 1,550 additions and 91 deletions.
4 changes: 2 additions & 2 deletions apps/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
},
"dependencies": {
"@flows/js": "0.1.0",
"@hookform/resolvers": "^3.4.2",
"@hookform/resolvers": "^3.6.0",
"@marsidev/react-turnstile": "^0.6.1",
"@monaco-editor/react": "^4.6.0",
"@radix-ui/react-dropdown-menu": "^2.0.6",
Expand All @@ -33,7 +33,7 @@
"@visx/tooltip": "^3.3.0",
"dayjs": "^1.11.11",
"icons": "workspace:*",
"monaco-editor": "^0.49.0",
"monaco-editor": "^0.50.0",
"next": "14.2.4",
"posthog-js": "^1.139.2",
"react": "^18.3.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const CDNSnippet: FC<Props> = async ({ projectId }) => {
</Text>
<CodeHighlight className={css({ margin: "0!", width: "100%" })}>
<pre>
<code className="index.html">{`<script>
<code className="index.html">{`<script type="module">
flows.init({ projectId: "${projectId}" });
</script>`}</code>
</pre>
Expand Down
18 changes: 18 additions & 0 deletions apps/app/src/app/(dashboard)/welcome-redirect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"use client";

import { useFetch } from "hooks/use-fetch";
import { useRouter } from "next/navigation";
import { useEffect } from "react";
import { routes } from "routes";

export const WelcomeRedirect = (): null => {
const { data } = useFetch("/me");
const router = useRouter();

useEffect(() => {
if (!data) return;
if (!data.finished_welcome) router.replace(routes.welcomeNewsletter);
}, [data, router]);

return null;
};
19 changes: 19 additions & 0 deletions apps/app/src/app/welcome/newsletter/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Flex } from "@flows/styled-system/jsx";
import { Text } from "ui";

import { SubscribeForm } from "./subscribe-form";

export default function WelcomeSubscribePage(): JSX.Element {
return (
<Flex flexDirection="column" gap="space24" maxW="400px" width="100%">
<Flex alignItems="center" flexDirection="column" gap="space4">
<Text variant="titleL">Subscribe to updates</Text>
<Text color="muted" align="center">
Flows are improving every month. These are the best ways to stay in the loop.
</Text>
</Flex>

<SubscribeForm />
</Flex>
);
}
91 changes: 91 additions & 0 deletions apps/app/src/app/welcome/newsletter/subscribe-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
"use client";

import { css } from "@flows/styled-system/css";
import { Box, Flex } from "@flows/styled-system/jsx";
import { mutate } from "hooks/use-fetch";
import { useSend } from "hooks/use-send";
import { api } from "lib/api";
import { useRouter } from "next/navigation";
import { Controller, type SubmitHandler, useForm } from "react-hook-form";
import { routes } from "routes";
import { links } from "shared";
import { Button, Switch, Text } from "ui";

type FormValues = {
marketingConsent: boolean;
};

export const SubscribeForm = (): JSX.Element => {
const { handleSubmit, control } = useForm<FormValues>({
defaultValues: { marketingConsent: false },
});
const router = useRouter();
const { send, loading } = useSend();
const onSubmit: SubmitHandler<FormValues> = async (data) => {
const requests: Promise<{ error?: Error }>[] = [
send(api["/me"]({ finished_welcome: true }), { errorMessage: null }),
];
if (data.marketingConsent)
requests.push(send(api["POST /newsletter"](), { errorMessage: "Failed to subscribe" }));

const responses = await Promise.all(requests);
if (responses.some((res) => !!res.error)) return;
await mutate("/me");
router.replace(routes.home);
};

return (
<form onSubmit={handleSubmit(onSubmit)}>
<Flex flexDirection="column" alignItems="center" width="100%">
<Box borderRadius="radius12" cardWrap="-" mb="space24">
<Flex flexDirection="column" gap="space16" padding="space24" borBottom="1px">
<Controller
control={control}
name="marketingConsent"
render={({ field }) => (
<Switch
checked={field.value}
onChange={field.onChange}
label={
<>
<Text weight="600" display="block">
Subscribe to our newsletter
</Text>
<Text as="span" variant="bodyXs" display="block" color="muted">
Email once a month about new features and changes
</Text>
</>
}
/>
)}
/>
</Flex>
<Flex justifyContent="space-between" alignItems="center" padding="space24">
<Flex flexDirection="column">
<Text weight="600">Follow us on Twitter</Text>
<Text variant="bodyXs" color="muted">
Tweets about features and tips
</Text>
</Flex>
<Button variant="secondary" asChild>
<a href={links.twitter} target="_blank" rel="noopener">
@flows_sh
</a>
</Button>
</Flex>
</Box>
<Button
className={css({
maxWidth: "200px",
width: "100%",
})}
loading={loading}
size="default"
type="submit"
>
Continue
</Button>
</Flex>
</form>
);
};
5 changes: 5 additions & 0 deletions apps/app/src/lib/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export type FlowVersion = Schemas["GetFlowVersionsDto"];
export type UpdateFlow = Schemas["UpdateFlowDto"];
export type CreateFlow = Schemas["CreateFlowDto"];
export type Me = Schemas["GetMeDto"];
export type UpdateMe = Schemas["UpdateMeDto"];
export type AcceptInviteResponse = Schemas["AcceptInviteResponseDto"];

export type Api = {
Expand Down Expand Up @@ -60,10 +61,12 @@ export type Api = {
"POST /projects/:projectId/flows": Endpoint<FlowPreview, [string, CreateFlow]>;
"DELETE /flows/:flowId": Endpoint<void, [string]>;
"/me": Endpoint<Me>;
"PATCH /me": Endpoint<void, [UpdateMe]>;
"DELETE /me": Endpoint<void>;
"DELETE /me/identities/:providerId": Endpoint<void, [string]>;
"POST /invites/:inviteId/accept": Endpoint<AcceptInviteResponse, [string]>;
"POST /invites/:inviteId/decline": Endpoint<void, [string]>;
"POST /newsletter": Endpoint<void>;

"/css/vars": Endpoint<string>;
"/css/template": Endpoint<string>;
Expand Down Expand Up @@ -112,13 +115,15 @@ export const api: Api = {
fetcher(`/projects/${projectId}/flows`, { method: "POST", body }),
"DELETE /flows/:flowId": (flowId) => fetcher(`/flows/${flowId}`, { method: "DELETE" }),
"/me": () => fetcher("/me"),
"PATCH /me": (body) => fetcher("/me", { method: "PATCH", body }),
"DELETE /me": () => fetcher("/me", { method: "DELETE" }),
"DELETE /me/identities/:providerId": (providerId) =>
fetcher(`/me/identities/${providerId}`, { method: "DELETE" }),
"POST /invites/:inviteId/accept": (inviteId) =>
fetcher(`/invites/${inviteId}/accept`, { method: "POST" }),
"POST /invites/:inviteId/decline": (inviteId) =>
fetcher(`/invites/${inviteId}/decline`, { method: "POST" }),
"POST /newsletter": () => fetcher("/newsletter", { method: "POST" }),

"/css/vars": () => fetcher("/css/vars"),
"/css/template": () => fetcher("/css/template"),
Expand Down
52 changes: 52 additions & 0 deletions apps/app/src/lib/api/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ export interface paths {
"/sdk/flows": {
get: operations["SdkController_getFlows"];
};
"/v2/sdk/flows": {
get: operations["SdkController_getFlowsV2"];
};
"/sdk/flows/{flowId}/draft": {
get: operations["SdkController_getPreviewFlow"];
};
Expand Down Expand Up @@ -87,6 +90,7 @@ export interface paths {
"/me": {
get: operations["UsersController_me"];
delete: operations["UsersController_deleteAccount"];
patch: operations["UsersController_updateMe"];
};
"/invites/{inviteId}/accept": {
post: operations["UsersController_acceptInvite"];
Expand All @@ -97,6 +101,9 @@ export interface paths {
"/waitlist": {
post: operations["UsersController_joinWaitlist"];
};
"/newsletter": {
post: operations["UsersController_joinNewsletter"];
};
"/me/identities/{providerId}": {
delete: operations["UsersController_deleteIdentity"];
};
Expand Down Expand Up @@ -124,6 +131,10 @@ export interface components {
userProperties?: Record<string, never>;
_incompleteSteps?: boolean;
};
GetSdkFlowsV2Dto: {
results: components["schemas"]["GetSdkFlowsDto"][];
error_message?: string;
};
CreateEventDto: {
/** @enum {string} */
type: "startFlow" | "nextStep" | "prevStep" | "tooltipError" | "cancelFlow";
Expand Down Expand Up @@ -370,10 +381,14 @@ export interface components {
role: "admin" | "user";
pendingInvites: components["schemas"]["Invite"][];
hasPassword: boolean;
finished_welcome: boolean;
};
AcceptInviteResponseDto: {
organization_id: string;
};
UpdateMeDto: {
finished_welcome?: boolean;
};
JoinWaitlistDto: {
email: string;
captcha_token: string;
Expand Down Expand Up @@ -434,6 +449,24 @@ export interface operations {
};
};
};
SdkController_getFlowsV2: {
parameters: {
query: {
projectId: string;
userHash?: string;
};
header: {
origin: string;
};
};
responses: {
200: {
content: {
"application/json": components["schemas"]["GetSdkFlowsV2Dto"];
};
};
};
};
SdkController_getPreviewFlow: {
parameters: {
query: {
Expand Down Expand Up @@ -898,6 +931,18 @@ export interface operations {
};
};
};
UsersController_updateMe: {
requestBody: {
content: {
"application/json": components["schemas"]["UpdateMeDto"];
};
};
responses: {
200: {
content: never;
};
};
};
UsersController_acceptInvite: {
parameters: {
path: {
Expand Down Expand Up @@ -936,6 +981,13 @@ export interface operations {
};
};
};
UsersController_joinNewsletter: {
responses: {
201: {
content: never;
};
};
};
UsersController_deleteIdentity: {
parameters: {
path: {
Expand Down
1 change: 1 addition & 0 deletions apps/app/src/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const routes = {
welcomeOrganization: (params: { organizationId: string }) => `/welcome/${params.organizationId}`,
welcomeOrganizationProject: (params: { organizationId: string; projectId: string }) =>
`/welcome/${params.organizationId}/${params.projectId}`,
welcomeNewsletter: "/welcome/newsletter",
userSettings: () => `/user/settings`,
organization: (params: { organizationId: string }) => `/org/${params.organizationId}`,
organizationSettings: (params: { organizationId: string }) =>
Expand Down
2 changes: 1 addition & 1 deletion apps/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"fastify": "^4.27.0",
"jsonwebtoken": "^9.0.2",
"lightningcss": "^1.25.1",
"loops": "^2.0.0",
"loops": "^2.1.1",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1",
"shared": "workspace:*",
Expand Down
25 changes: 24 additions & 1 deletion apps/backend/src/email/email.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ import { LoopsClient } from "loops";

import { type OrganizationUsageAlertType } from "../types/organization";

const MAILING_LISTS = {
// cspell:disable-next-line
onboarding: "clxiswbsb00rt0ljwag785nf6",
// cspell:disable-next-line
newsletter: "clxisx0kc00od0ll6hevrbx8j",
};

@Injectable()
export class EmailService {
get loops(): LoopsClient {
Expand Down Expand Up @@ -78,6 +85,22 @@ export class EmailService {
}

async signedUp({ email }: { email: string }): Promise<ReturnType<LoopsClient["sendEvent"]>> {
return this.loops.sendEvent({ email, eventName: "signup" });
return this.loops.sendEvent({
email,
eventName: "signup",
mailingLists: { [MAILING_LISTS.onboarding]: true },
});
}

async joinNewsletter({
email,
}: {
email: string;
}): Promise<ReturnType<LoopsClient["sendEvent"]>> {
return this.loops.sendEvent({
email,
eventName: "newsletter_signup",
mailingLists: { [MAILING_LISTS.newsletter]: true },
});
}
}
Loading

0 comments on commit ac7f124

Please sign in to comment.