Skip to content

Commit

Permalink
add: org invitation accept page
Browse files Browse the repository at this point in the history
  • Loading branch information
majkshkurti committed Oct 20, 2023
1 parent e4a55b1 commit 4b3fabe
Show file tree
Hide file tree
Showing 15 changed files with 359 additions and 56 deletions.
84 changes: 49 additions & 35 deletions apps/web/app/[lng]/(dashboard)/settings/account/profile/page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
"use client";

import React from "react";
import { Box } from "@mui/material";
import { Box, Stack, Typography } from "@mui/material";
import { v4 } from "uuid";
import { TextField, Grid, Button, useTheme, Card } from "@mui/material";
import { useTranslation } from "@/i18n/client";

interface tempProfileInfoType {
label: string;
value: string;
editable: boolean;
}

const Profile = () => {
const Profile = ({ params: { lng } }) => {
const theme = useTheme();
const { t } = useTranslation(lng, "dashboard");

const informatoryData: tempProfileInfoType[] = [
{
Expand Down Expand Up @@ -53,8 +55,20 @@ const Profile = () => {
];

return (
<Box sx={{marginBottom: "100px" }}>
<Card sx={{padding: `${theme.spacing(6)} ${theme.spacing(3)}`}}>
<Box sx={{ p: 4 }}>
<Box component="form">
<Stack spacing={theme.spacing(6)}>
<Box>
<Typography variant="body1" fontWeight="bold">
{t("personal_information")}
</Typography>
<Typography variant="caption">
{t("update_personal_information")}
</Typography>
</Box>
</Stack>
</Box>
<Card sx={{ padding: `${theme.spacing(6)} ${theme.spacing(3)}` }}>
<Grid container spacing={2}>
{informatoryData.map((infoData) => (
<Grid key={v4()} item xs={12} sm={6}>
Expand All @@ -75,40 +89,40 @@ const Profile = () => {
</Grid>
))}
</Grid>
</Card>
<Box
</Card>
<Box
sx={{
margin: `0px ${theme.spacing(3)}px`,
marginTop: "100px",
}}
>
<Button
variant="outlined"
color="error"
sx={{
margin: `0px ${theme.spacing(3)}px`,
marginTop: "100px",
display: "block",
width: "100%",
padding: "10px",
borderRadius: 1,
margin: `${theme.spacing(3)} 0px`,
}}
>
<Button
variant="outlined"
color="error"
sx={{
display: "block",
width: "100%",
padding: "10px",
borderRadius: 1,
margin: `${theme.spacing(3)} 0px`,
}}
>
Deactivate
</Button>
<Button
variant="contained"
color="error"
sx={{
display: "block",
width: "100%",
padding: "10px",
margin: `${theme.spacing(3)} 0px`,
borderRadius: 1,
}}
>
Delete
</Button>
</Box>
Deactivate
</Button>
<Button
variant="contained"
color="error"
sx={{
display: "block",
width: "100%",
padding: "10px",
margin: `${theme.spacing(3)} 0px`,
borderRadius: 1,
}}
>
Delete
</Button>
</Box>
</Box>
);
};
Expand Down
6 changes: 6 additions & 0 deletions apps/web/app/[lng]/(dashboard)/settings/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ const SettingsLayout = (props: SettingsLayoutProps) => {
label: "Account",
current: pathname?.includes("/account"),
},
{
link: "/settings/teams",
icon: ICON_NAME.USERS,
label: "Teams",
current: pathname?.includes("/teams"),
},
{
link: "/settings/organization",
icon: ICON_NAME.ORGANIZATION,
Expand Down
3 changes: 3 additions & 0 deletions apps/web/app/[lng]/(dashboard)/settings/teams/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Teams() {
return <>Teams Page</>;
}
9 changes: 8 additions & 1 deletion apps/web/app/[lng]/auth/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,16 @@ export default function Login() {
status === "unauthenticated" ||
session?.error === "RefreshAccessTokenError"
) {
const currentUrl = new URL(window.location.href);
const searchParams = new URLSearchParams(currentUrl.search);
const path = searchParams.get("callbackUrl");
const origin = currentUrl.origin;

signIn(
"keycloak",
{},
{
callbackUrl: `${origin}${path ?? "/"}`,
},
{
theme: theme.palette.mode,
},
Expand Down
6 changes: 1 addition & 5 deletions apps/web/app/[lng]/onboarding/organization/create/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,10 @@ import { useOrganizationSetup } from "@/hooks/onboarding/OrganizationCreate";
import LoadingButton from "@mui/lab/LoadingButton";
import { useRouter } from "next/navigation";
import { createOrganization } from "@/lib/api/organizations";
import type { ResponseResult } from "@/types/common";

type FormData = z.infer<typeof postOrganizationSchema>;

type ResponseResult = {
message: string;
status?: "error" | "success";
};
const STEPS = [
"new_organization",
"organization_profile",
Expand Down Expand Up @@ -123,7 +120,6 @@ export default function OrganizationOnBoarding({ params: { lng } }) {
}, [watchFormValues]);

async function onSubmit(data: FormData) {
console.log(data);
setResponseResult({ message: "", status: undefined });
setIsBusy(true);
try {
Expand Down
183 changes: 183 additions & 0 deletions apps/web/app/[lng]/onboarding/organization/invite/[inviteId]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
"use client";
import {
Alert,
Avatar,
Box,
Link,
Stack,
Typography,
useTheme,
} from "@mui/material";
import { useMemo, useState } from "react";
import AuthContainer from "@p4b/ui/components/AuthContainer";
import AuthLayout from "@p4b/ui/components/AuthLayout";
import { useSession } from "next-auth/react";
// import { useTranslation } from "@/i18n/client";
import { useRouter } from "next/navigation";

import {
acceptInvitation,
declineInvitation,
useInvitations,
} from "@/lib/api/users";
import type { GetInvitationsQueryParams } from "@/lib/validations/user";
import { Loading } from "@p4b/ui/components/Loading";
import type { ResponseResult } from "@/types/common";
import { useTranslation } from "@/i18n/client";
import { LoadingButton } from "@mui/lab";

export default function OrganizationInviteJoin({ params: { lng, inviteId } }) {
const theme = useTheme();
const [queryParams, _setQueryParams] = useState<GetInvitationsQueryParams>({
type: "organization",
invitation_id: inviteId,
});
const { invitations, isLoading } = useInvitations(queryParams);
console.log(invitations);
const { status, data: session, update } = useSession();
const router = useRouter();
const [isBusy, setIsBusy] = useState(false);
const { t } = useTranslation(lng, ["onboarding", "common"]);
const [responseResult, setResponseResult] = useState<ResponseResult>({
message: "",
status: undefined,
});

const invitation = useMemo(() => {
if (
invitations?.items &&
invitations?.items?.length > 0 &&
invitations?.items?.[0].payload?.user_email === session?.user?.email
)
return invitations?.items?.[0];
}, [invitations, session]);

async function handleAcceptInvite() {
setIsBusy(true);
try {
await acceptInvitation(inviteId);
} catch (_error) {
setResponseResult({
message: t("onboarding:invite_accept_error"),
status: "error",
});
} finally {
setIsBusy(false);
}
update();
router.push("/");
}

async function handleDeclineInvite() {
setIsBusy(true);
try {
await declineInvitation(inviteId);
} catch (_error) {
setResponseResult({
message: t("onboarding:invite_decline_error"),
status: "error",
});
} finally {
setIsBusy(false);
}
update();
router.push("/");
}

return (
<AuthLayout>
<>
{status == "authenticated" && !isLoading && (
<AuthContainer
headerTitle={
<>
{invitation?.payload?.name && (
<Stack spacing={4} alignItems="center">
<Typography variant="h5">
You have been invited to join the organization{": "}
<b>{invitation?.payload?.name}</b>
</Typography>
<Avatar
sx={{ width: 50, height: 50 }}
alt={invitation?.payload?.avatar || "Org"}
src={invitation?.payload?.avatar}
/>
</Stack>
)}
{!invitation && (
<Typography variant="h5">We are sorry...</Typography>
)}
</>
}
headerAlert={
responseResult.status && (
<Alert severity={responseResult.status}>
{responseResult.message}
</Alert>
)
}
body={
<>
{!invitation && (
<Typography variant="body1">
We could not find the invitation you are looking for. Please
try with a valid invitation link or another account.
</Typography>
)}
{invitation && invitation.status == "pending" && (
<Typography variant="body1">
Please confirm your invitation to join the organization by
clicking the button below.
</Typography>
)}
</>
}
footer={
<>
<Box
sx={{
mt: theme.spacing(6),
}}
>
{!invitation && (
<Link id="backToApplication" href="/">
« Back to Application
</Link>
)}
{invitation && (
<>
<LoadingButton
loading={isBusy}
variant="contained"
fullWidth
disabled={isBusy}
onClick={handleAcceptInvite}
sx={{
mb: theme.spacing(2),
}}
>
Join
</LoadingButton>
<LoadingButton
fullWidth
disabled={isBusy}
onClick={handleDeclineInvite}
variant="text"
sx={{
color: theme.palette.error.main,
}}
>
Decline
</LoadingButton>
</>
)}
</Box>
</>
}
/>
)}
{isLoading && <Loading />}
</>
</AuthLayout>
);
}
5 changes: 0 additions & 5 deletions apps/web/app/[lng]/onboarding/organization/page.tsx

This file was deleted.

3 changes: 3 additions & 0 deletions apps/web/app/api/auth/[...nextauth]/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ export const options: NextAuthOptions = {
jwt: {
maxAge: 1 * 60, // 1 minute, same as in Keycloak
},
pages: {
signIn: "/auth/login",
},
session: {
strategy: "jwt",
maxAge: 30 * 24 * 60 * 60, // 30 days : 2592000, same as in Keycloak
Expand Down
5 changes: 4 additions & 1 deletion apps/web/i18n/locales/en/dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@
"light": "Light",
"measurement_unit": "Measurement Unit",
"metric": "Metric",
"imperial": "Imperial"
"imperial": "Imperial",
"personal_information": "Personal Information",
"update_personal_information": "Update personal information"

}
4 changes: 3 additions & 1 deletion apps/web/i18n/locales/en/onboarding.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,7 @@
"organization_subscribe_to_newsletter": "Stay in touch with our latest updates",
"organization_onboarding_trial_note": "Note: Your 14-day trial starts after you create your organization.",
"organization_accept_terms": "By signing up, you agree to our Terms of Service and Privacy Policy.",
"organization_creation_error": "Something went wrong. Please try again later."
"organization_creation_error": "Something went wrong. Please try again later.",
"invite_accept_error": "Something went wrong. Please try again later.",
"invite_decline_error": "Something went wrong. Please try again later."
}
1 change: 1 addition & 0 deletions apps/web/lib/api/organizations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ export const createOrganization = async (
}
return await response.json();
};

Loading

0 comments on commit 4b3fabe

Please sign in to comment.