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

[env/github] map SAML SSO data from Okta into user's profile data #1667

Merged
merged 26 commits into from
Jun 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5247fa5
Adds mapping application to the profile
mike-lvov Jun 25, 2021
9ab49a0
Adds functional prototype
mike-lvov Jun 25, 2021
00d313a
Adds comments + explanations
mike-lvov Jun 25, 2021
1835ebd
utils for localStorage
mike-lvov Jun 27, 2021
15dfaa4
Adds SSO saml data integration
mike-lvov Jun 28, 2021
40c2047
Merge branch 'env/github' into feature/apply-SAML-mappings
mike-lvov Jun 28, 2021
471e08b
Removes hardcoded text
mike-lvov Jun 28, 2021
5b2e692
Merge branch 'env/github' into feature/apply-SAML-mappings
mike-lvov Jun 28, 2021
9e85c8b
Update src/utils/profile.ts
mike-lvov Jun 28, 2021
2d4f261
Removes Mapping type; Replaces mapping fn
mike-lvov Jun 28, 2021
8c56ac8
Refactors avatar images
mike-lvov Jun 28, 2021
c77cd25
Replaces localStorage with firebase + useAsync
mike-lvov Jun 28, 2021
e3eee37
Merge branch 'env/github' into feature/apply-SAML-mappings
mike-lvov Jun 28, 2021
3da671c
Fixes data display + Adds loading
mike-lvov Jun 28, 2021
906213a
Merge branch 'feature/apply-SAML-mappings' of github.com:sparkletown/…
mike-lvov Jun 28, 2021
d4d5ad9
Removes comment
mike-lvov Jun 28, 2021
124ffac
Fixes the incorrectly displayed value
mike-lvov Jun 28, 2021
a27e97c
Apply suggestions from code review
mike-lvov Jun 28, 2021
c90d0f1
Update src/components/organisms/UserProfileModal/UserProfileModal.tsx
mike-lvov Jun 28, 2021
36f9ee2
Apply review suggestions
mike-lvov Jun 28, 2021
fc47408
Adds editing functionality
mike-lvov Jun 28, 2021
28aeb73
Changes the icon to GitHub
mike-lvov Jun 28, 2021
4ce9fa3
Final polishes
mike-lvov Jun 28, 2021
b1a4961
Wrapps inputs into label
mike-lvov Jun 28, 2021
41dc9b2
Replaces h6 with p
mike-lvov Jun 28, 2021
b294918
Returns a fn
mike-lvov Jun 28, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/api/profile.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Bugsnag from "@bugsnag/js";
import firebase from "firebase/app";
import { TalkShowStudioExperience, UserStatus, ProfileLink } from "types/User";

import { TalkShowStudioExperience, UserStatus, ProfileLink } from "types/User";
import { VenueEvent } from "types/venues";

import { WithVenueId } from "utils/id";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import React, { useCallback, useMemo, useRef, useState } from "react";
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import { useFirebase } from "react-redux-firebase";
import { useAsync } from "react-use";
import { UserInfo } from "firebase/app";
Expand All @@ -11,6 +17,7 @@ import {
} from "settings";

import { resizeFile } from "utils/image";
import { isDefined } from "utils/types";

import { useSovereignVenueId } from "hooks/useSovereignVenueId";

Expand All @@ -27,6 +34,7 @@ export interface ProfilePictureInputProps {
pictureUrl: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
register: any;
githubHandle?: string;
}

export const ProfilePictureInput: React.FunctionComponent<ProfilePictureInputProps> = ({
Expand All @@ -36,6 +44,7 @@ export const ProfilePictureInput: React.FunctionComponent<ProfilePictureInputPro
errors,
pictureUrl,
register,
githubHandle,
}) => {
const [isPictureUploading, setIsPictureUploading] = useState(false);
const [error, setError] = useState("");
Expand Down Expand Up @@ -92,6 +101,16 @@ export const ProfilePictureInput: React.FunctionComponent<ProfilePictureInputPro
setValue("pictureUrl", pictureUrlRef, true);
};

const githubImageSrc =
githubHandle && `https://github.com/${githubHandle}.png?size=120`;

// Set GitHub image as a default picture
useEffect(() => {
if (!githubImageSrc || pictureUrl) return;

setValue("pictureUrl", githubImageSrc, true);
}, [githubImageSrc, setValue, pictureUrl]);

const uploadDefaultAvatar = useCallback(
async (avatar: string) => {
setValue("pictureUrl", avatar, true);
Expand All @@ -107,21 +126,25 @@ export const ProfilePictureInput: React.FunctionComponent<ProfilePictureInputPro
? customAvatars
: DEFAULT_AVATARS;

const avatarImages = useMemo(() => {
return defaultAvatars.map((avatar, index) => (
<div
key={`${avatar}-${index}`}
className="profile-picture-preview-container"
onClick={() => uploadDefaultAvatar(avatar)}
>
<img
src={avatar}
className="profile-icon profile-picture-preview"
alt={`default avatar ${index}`}
/>
</div>
));
}, [defaultAvatars, uploadDefaultAvatar]);
const avatarImages = useMemo(
() =>
[githubImageSrc, ...defaultAvatars]
.filter(isDefined)
.map((avatarSrc, index) => (
<div
key={`${avatarSrc}-${index}`}
className="profile-picture-preview-container"
onClick={() => uploadDefaultAvatar(avatarSrc)}
>
<img
src={avatarSrc}
className="profile-icon profile-picture-preview"
alt={`default avatar ${index}`}
/>
</div>
)),
[defaultAvatars, githubImageSrc, uploadDefaultAvatar]
);

return (
<div className="profile-picture-upload-form">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ $button-height: 30px;
line-height: $spacing--xl;
color: opaque-white(0.5);
text-align: start;
margin-bottom: $spacing--md;
}

&__edit-input-title {
font-size: $font-size--md;
margin-bottom: $spacing--lg;
opacity: 0.8;
width: 100%;
}

&__question {
Expand All @@ -29,7 +37,7 @@ $button-height: 30px;

&__input-container-name {
height: $submit-button-diameter;
margin-bottom: $spacing--xl;
margin-top: $spacing--sm;
}

&__input-name {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ export const EditProfileForm: React.FunctionComponent<EditProfileFormProps> = ({
const defaultValues = {
partyName: profile?.partyName,
pictureUrl: profile?.pictureUrl || DEFAULT_PROFILE_IMAGE,
realName: profile?.realName,
companyTitle: profile?.companyTitle,
companyDepartment: profile?.companyDepartment,
};

profileQuestions &&
Expand Down Expand Up @@ -90,14 +93,50 @@ export const EditProfileForm: React.FunctionComponent<EditProfileFormProps> = ({
<div className="EditProfileForm">
<h1 className="EditProfileForm__title">Edit profile</h1>
<form onSubmit={handleSubmit(onSubmit)} className="form">
<InputField
containerClassName="EditProfileForm__input-container-name"
inputClassName="EditProfileForm__input-name"
name="partyName"
placeholder="Your display name"
error={errors.partyName}
ref={register()}
/>
<label className="EditProfileForm__edit-input-title">
Display name
<InputField
containerClassName="EditProfileForm__input-container-name"
inputClassName="EditProfileForm__input-name"
name="partyName"
placeholder="Your display name"
error={errors.partyName}
ref={register()}
/>
</label>

<label className="EditProfileForm__edit-input-title">
Real name
<InputField
containerClassName="EditProfileForm__input-container-name"
inputClassName="EditProfileForm__input-name"
name="realName"
placeholder="Your real name"
ref={register()}
/>
</label>

<label className="EditProfileForm__edit-input-title">
Department
<InputField
containerClassName="EditProfileForm__input-container-name"
inputClassName="EditProfileForm__input-name"
name="companyDepartment"
placeholder="Your department"
ref={register()}
/>
</label>

<label className="EditProfileForm__edit-input-title">
Title
<InputField
containerClassName="EditProfileForm__input-container-name"
inputClassName="EditProfileForm__input-name"
name="companyTitle"
placeholder="Your title"
ref={register()}
/>
</label>

{user && venueId && (
<ProfilePictureInput
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@ $profile-link--padding: 6px 18px;
background: $secondary--light;
}
}
}

.question {
margin-bottom: 0;
.no-margin {
margin-bottom: 0;
}
}

.light {
Expand Down
46 changes: 35 additions & 11 deletions src/components/organisms/UserProfileModal/UserProfileModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,15 @@ export const UserProfileModal: React.FC<UserProfileModalProps> = ({
closeUserProfileModal,
} = useProfileModalControls();

const chosenUserId = selectedUserProfile?.id;
const {
id: chosenUserId,
profileLinks,
pictureUrl,
partyName,
realName,
companyDepartment,
companyTitle,
} = selectedUserProfile ?? {};

const profileQuestions = venue?.profile_questions;

Expand All @@ -67,8 +75,8 @@ export const UserProfileModal: React.FC<UserProfileModalProps> = ({

return (
<React.Fragment key={question.text}>
<p className="light question">{question.text}</p>
<h6>{questionAnswer}</h6>
<p className="light no-margin">{question.text}</p>
<p className="h6">{questionAnswer}</p>
</React.Fragment>
);
})
Expand All @@ -78,7 +86,7 @@ export const UserProfileModal: React.FC<UserProfileModalProps> = ({

const renderedProfileLinks = useMemo(
() =>
selectedUserProfile?.profileLinks?.map((link) => (
profileLinks?.map((link) => (
<a
key={link.title}
className="UserProfileModal__profile-link"
Expand All @@ -89,7 +97,7 @@ export const UserProfileModal: React.FC<UserProfileModalProps> = ({
{link.title}
</a>
)),
[selectedUserProfile?.profileLinks]
[profileLinks]
);

if (!selectedUserProfile || !chosenUserId || !user) {
Expand All @@ -109,7 +117,7 @@ export const UserProfileModal: React.FC<UserProfileModalProps> = ({
<div className="profile-pic">
{/* @debt Refactor this to use our useImage hook? Or just UserAvatar / UserProfilePicture directly? */}
<img
src={selectedUserProfile.pictureUrl || DEFAULT_PROFILE_PIC}
src={pictureUrl ?? DEFAULT_PROFILE_PIC}
alt="profile"
onError={(e) => {
(e.target as HTMLImageElement).onerror = null;
Expand All @@ -124,24 +132,40 @@ export const UserProfileModal: React.FC<UserProfileModalProps> = ({
/>
</div>
<div className="profile-text">
<h2 className="italic">
{selectedUserProfile.partyName || DEFAULT_PARTY_NAME}
</h2>
<h2 className="italic">{partyName ?? DEFAULT_PARTY_NAME}</h2>
</div>
</div>
<div className="profile-extras">
{renderedProfileQuestionAnswers}
</div>
<div>{renderedProfileLinks}</div>
{realName && (
<>
<p className="light no-margin">Full Name</p>
<p className="h6">{realName}</p>
</>
)}
{companyDepartment && (
<>
<p className="light no-margin">Department</p>
<p className="h6">{companyDepartment}</p>
</>
)}
{companyTitle && (
<>
<p className="light no-margin">Title</p>
<p className="h6">{companyTitle}</p>
</>
)}
{ENABLE_SUSPECTED_LOCATION && (
<div className="profile-location">
<p className="question">Suspected Location:</p>
<h6 className="location">
<p className="h6 location">
<SuspectedLocation
user={selectedUserProfile}
currentVenue={venue}
/>
</h6>
</p>
</div>
)}
</div>
Expand Down
26 changes: 21 additions & 5 deletions src/hooks/useSAMLSignIn.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
import { useCallback } from "react";
import Bugsnag from "@bugsnag/js";
import { useAsyncFn } from "react-use";

import firebase from "firebase/app";

export const useSAMLSignIn = (samlAuthProviderId?: string) => {
import { ReactHook } from "types/utility";

export interface UseSAMLSignInProps {
samlAuthProviderId?: string;
}

export interface UseSAMLSignInReturn {
hasSamlAuthProviderId: boolean;
signInWithSAML: () => void;
isSigningIn: boolean;
}

export const useSAMLSignIn: ReactHook<
UseSAMLSignInProps,
UseSAMLSignInReturn
> = ({ samlAuthProviderId }) => {
const hasSamlAuthProviderId = samlAuthProviderId !== undefined;

const signInWithSAML = useCallback(() => {
const [{ loading }, signInWithSAML] = useAsyncFn(async () => {
if (!samlAuthProviderId) return;

const SAMLAuthProvider = new firebase.auth.SAMLAuthProvider(
samlAuthProviderId
);

firebase
return firebase
.auth()
.signInWithPopup(SAMLAuthProvider)
.catch((err) => {
Expand All @@ -27,5 +43,5 @@ export const useSAMLSignIn = (samlAuthProviderId?: string) => {
});
}, [samlAuthProviderId]);

return { signInWithSAML, hasSamlAuthProviderId };
return { signInWithSAML, hasSamlAuthProviderId, isSigningIn: loading };
};
Loading