Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions .storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ module.exports = {
use: ["file-loader"]
})
config.resolve.fallback = { fs: false, path: false }
const path = require("path")
const webpack = require("webpack")
config.plugins.push(
new webpack.NormalModuleReplacementPlugin(
/components\/db\/profile\/profile(\.tsx?)?$/,
path.resolve(__dirname, "../stories/__mocks__/db/profile.ts")
)
)
return config
},

Expand Down
10 changes: 7 additions & 3 deletions components/shared/PhoneVerificationModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,17 @@ const AUTH_ERROR_CODE_TO_KEY: Record<string, string> = {
export function PhoneVerificationModal({
show,
onHide,
onVerified
}: Pick<ModalProps, "show" | "onHide"> & { onVerified?: () => void }) {
onVerified,
initialStep = "phone"
}: Pick<ModalProps, "show" | "onHide"> & {
onVerified?: () => void
initialStep?: "phone" | "code" | "success"
}) {
const { t } = useTranslation("auth")
const { user } = useAuth()
const completePhoneVerification = useCompletePhoneVerification()

const [step, setStep] = useState<"phone" | "code" | "success">("phone")
const [step, setStep] = useState<"phone" | "code" | "success">(initialStep)
const [phone, setPhone] = useState("")
const [code, setCode] = useState("")
const [error, setError] = useState<string | null>(null)
Expand Down
89 changes: 89 additions & 0 deletions stories/__mocks__/db/profile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { Profile } from "components/db/profile/types"

export const mockProfile: Profile = {
topicName: "Environment, Education",
role: "user",
fullName: "Sol R. Panels",
email: "iveseenthelight@example.com",
representative: {
id: "rep-123",
name: "Polly Tician",
district: "5th Middlesex"
},
senator: {
id: "sen-123",
name: "Phil E. Buster",
district: "Middlesex and Suffolk"
},
public: true,
about: "Environmental advocate based in Cambridge, MA.",
location: "Cambridge, MA",
phoneVerified: false
}

export function usePublicProfile(_uid?: string, _verifyisorg?: boolean) {
return {
result: mockProfile,
loading: false,
error: undefined,
execute: async () => mockProfile,
currentPromise: null,
currentParams: null,
status: "success" as const
}
}

const noop = async () => {}

export function useProfile() {
return {
loading: false,
profile: mockProfile,
updatingRep: false,
updatingSenator: false,
updatingIsPublic: false,
updatingNotification: false,
updatingIsOrganization: false,
updatingAbout: false,
updatingFullName: false,
updatingProfileImage: false,
updatingOrgCategory: false,
updatingBillsFollowing: false,
updatingContactInfo: {
publicEmail: false,
publicPhone: false,
website: false
},
updatingSocial: {
linkedIn: false,
twitter: false,
instagram: false,
fb: false,
blueSky: false,
mastodon: false
},
updateSenator: noop,
updateRep: noop,
updateIsPublic: noop,
updateNotification: noop,
updateIsOrganization: noop,
updateAbout: noop,
updateFullName: noop,
updateProfileImage: noop,
updateSocial: noop,
updateContactInfo: noop,
updateOrgCategory: noop,
updateBillsFollowing: noop
}
}

export type ProfileHook = ReturnType<typeof useProfile>

export function useUser() {}

export const profileRef = (_uid: string) => ({} as any)
export const profileImageRef = (_uid: string) => ({} as any)
export const profileImageUrl = async (_uid: string) => ""
export const updateProfileImage = noop
export const setProfile = noop
export const getProfile = async (_uid: string) => mockProfile
57 changes: 57 additions & 0 deletions stories/organisms/PhoneVerificationModal.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Meta, StoryObj } from "@storybook/react"
import { PhoneVerificationModal } from "components/shared/PhoneVerificationModal"
import { Providers } from "components/providers"
import { wrapper } from "components/store"
import { Provider as Redux } from "react-redux"

const meta: Meta = {
title: "Organisms/PhoneVerificationModal",
component: PhoneVerificationModal,
decorators: [
(Story, ...rest) => {
const { store } = wrapper.useWrappedStore(...rest)

return (
<Redux store={store}>
<Providers>
<Story />
</Providers>
</Redux>
)
}
]
}

export default meta

type Story = StoryObj<typeof PhoneVerificationModal>

export const PhoneStep: Story = {
args: {
show: true,
onHide: () => {},
onVerified: () => {},
initialStep: "phone"
},
name: "Phone Step"
}

export const CodeStep: Story = {
args: {
show: true,
onHide: () => {},
onVerified: () => {},
initialStep: "code"
},
name: "Code Step"
}

export const SuccessStep: Story = {
args: {
show: true,
onHide: () => {},
onVerified: () => {},
initialStep: "success"
},
name: "Success Step"
}
43 changes: 43 additions & 0 deletions stories/organisms/VerifyAccountSection.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Meta, StoryObj } from "@storybook/react"
import { User } from "firebase/auth"
import { VerifyAccountSection } from "components/shared/VerifyAccountSection"
import { Providers } from "components/providers"
import { wrapper } from "components/store"
import { Provider as Redux } from "react-redux"

const meta: Meta = {
title: "Organisms/VerifyAccountSection",
component: VerifyAccountSection,
decorators: [
(Story, ...rest) => {
const { store, props } = wrapper.useWrappedStore(...rest)

return (
<Redux store={store}>
<Providers>
<Story />
</Providers>
</Redux>
)
}
]
}

export default meta

type Story = StoryObj<typeof VerifyAccountSection>

export const Primary: Story = {
args: {
user: { emailVerified: false } as User,
profile: {
topicName: "Your Topic Name",
role: "user",
fullName: "Matt Doe",
email: "anotherMatt@example.com",
phoneVerified: false
},
className: ""
},
name: "VerifyAccountSection"
}
91 changes: 91 additions & 0 deletions stories/pages/ProfilePage.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { Meta, StoryObj } from "@storybook/react"
import { configureStore } from "@reduxjs/toolkit"
import { User } from "firebase/auth"
import { RouterContext } from "next/dist/shared/lib/router-context.shared-runtime"
import { NextRouter } from "next/router"
import { Provider as Redux } from "react-redux"
import { reducer as auth } from "components/auth/redux"
import { api } from "components/db/api"
import { reducer as profile } from "components/db/profile/redux"
import { reducer as publish } from "components/publish/redux"
import { slice as testimonyDetail } from "components/testimony/TestimonyDetailPage"
import { ProfilePage } from "components/ProfilePage"

const PROFILE_UID = "mock-profile-uid"

const mockRouter = {
basePath: "",
pathname: "/profile/[id]",
route: "/profile/[id]",
query: { phoneVerificationUI: "enabled" },
asPath: `/profile/${PROFILE_UID}`,
push: async () => true,
replace: async () => true,
reload: () => {},
back: () => {},
forward: () => {},
prefetch: async () => undefined,
beforePopState: () => null,
events: { on: () => {}, off: () => {}, emit: () => {} },
isFallback: false,
isLocaleDomain: false,
isPreview: false,
isReady: true,
locale: "en",
locales: ["en"],
defaultLocale: "en",
domainLocales: []
} as unknown as NextRouter

const createMockStore = (userUid: string, emailVerified: boolean) =>
configureStore({
reducer: {
[api.reducerPath]: api.reducer,
auth,
profile,
publish,
[testimonyDetail.name]: testimonyDetail.reducer
},
preloadedState: {
auth: {
user: { uid: userUid, emailVerified } as unknown as User,
claims: { role: "user" as const },
authenticated: true,
authFlowStep: null,
loading: false
}
},
middleware: getDefaultMiddleware =>
getDefaultMiddleware({ serializableCheck: false }).concat(api.middleware)
})

const meta: Meta<typeof ProfilePage> = {
title: "Pages/ProfilePage",
component: ProfilePage
}

export default meta

type Story = StoryObj<typeof ProfilePage>

export const OwnProfile: Story = {
render: () => (
<RouterContext.Provider value={mockRouter}>
<Redux store={createMockStore(PROFILE_UID, false)}>
<ProfilePage id={PROFILE_UID} />
</Redux>
</RouterContext.Provider>
),
name: "Own Profile"
}

export const AnothersProfile: Story = {
render: () => (
<RouterContext.Provider value={mockRouter}>
<Redux store={createMockStore("mock-viewer-uid", false)}>
<ProfilePage id={PROFILE_UID} />
</Redux>
</RouterContext.Provider>
),
name: "Another's Profile"
}
Loading