diff --git a/components/EditProfilePage/PersonalInfoTab.tsx b/components/EditProfilePage/PersonalInfoTab.tsx index b6d70364c..111aa5038 100644 --- a/components/EditProfilePage/PersonalInfoTab.tsx +++ b/components/EditProfilePage/PersonalInfoTab.tsx @@ -10,7 +10,7 @@ import { TooltipButton } from "components/buttons" import { useTranslation } from "next-i18next" import styled from "styled-components" -type UpdateProfileData = { +export type UpdateProfileData = { fullName: string aboutYou: string twitter: string @@ -37,7 +37,7 @@ type Props = { legislatorsProps?: YourLegislatorsProps } -async function updateProfile( +export async function updateProfile( { profile, actions, uid }: Props, data: UpdateProfileData ) { diff --git a/components/db/profile/urlCleanup.ts b/components/db/profile/urlCleanup.ts index 26d09b13a..f2fe17e5c 100644 --- a/components/db/profile/urlCleanup.ts +++ b/components/db/profile/urlCleanup.ts @@ -7,7 +7,7 @@ export function cleanSocialLinks(network: keyof SocialLinks, link: string) { const index: number = path.indexOf(".com/") + 5 path = path.substring(index) } - if (network === "mastodon" && path.startsWith("@")) { + if (path && network === "mastodon" && path.startsWith("@")) { path = path.substring(1) } } diff --git a/components/legislator/LegislatorPage.tsx b/components/legislator/LegislatorPage.tsx index fbf6b9113..e43ae82e7 100644 --- a/components/legislator/LegislatorPage.tsx +++ b/components/legislator/LegislatorPage.tsx @@ -348,7 +348,7 @@ export function LegislatorPage(props: { id: string }) { - + diff --git a/components/legislator/SidebarComponents/Biography.tsx b/components/legislator/SidebarComponents/Biography.tsx index 90cf3f5e0..32e4e6440 100644 --- a/components/legislator/SidebarComponents/Biography.tsx +++ b/components/legislator/SidebarComponents/Biography.tsx @@ -1,3 +1,152 @@ -export function Biography() { - return
- Biography
+import { useTranslation } from "next-i18next" +import { useEffect, useState } from "react" +import { useForm } from "react-hook-form" +import styled from "styled-components" + +import { Form, Row, Spinner } from "../../bootstrap" +import { Profile, ProfileHook, useProfile } from "../../db" +import Input from "../../forms/Input" + +import { useAuth } from "components/auth" +import { + updateProfile, + UpdateProfileData +} from "components/EditProfilePage/PersonalInfoTab" + +const BioBlock = styled.div` + background-color: white; + border: "1px #ced4da solid"; + border-radius: 5px; + font-size: 11px; + margin-top: 8px; + padding: 8px 16px; +` + +const BioButton = styled.button` + font-size: 9px; + padding: 2px; +` + +const BioTitle = styled.div` + font-weight: 700; + color: #0b0a3e; + text-transform: uppercase; + letter-spacing: 0.05em; + margin-bottom: 10px; +` + +export function Biography({ + pageId, + publicProfile +}: { + pageId: string + publicProfile: Profile | undefined +}) { + const { user } = useAuth() + const uid = user?.uid + const pageOwnerResult = useProfile() + + let pageOwner = false + + if (uid === pageId) { + pageOwner = true + } + + if (pageOwnerResult.loading) { + return ( + + + + ) + } + + if (pageOwnerResult.profile && pageOwner) { + // the user is the legislator whose page this is + // therefore they get edit privledges + return ( + + ) + } + + if (publicProfile) { + // the user is not the legislator whose page this is + // therefore they get read-only privledges + return + } +} + +function EditableBiography({ + actions, + pageId, + profile +}: { + actions: ProfileHook + pageId: string + profile: Profile +}) { + const { + register, + formState: { errors, isDirty }, + handleSubmit + } = useForm() + + const { about }: Profile = profile + + const onSubmit = handleSubmit(async update => { + await updateProfile({ profile, actions }, update) + location.assign(`/legislators/profile?id=${pageId}`) + setFormUpdated(false) + }) + + const { t } = useTranslation("legislators") + const [formUpdated, setFormUpdated] = useState(false) + + useEffect(() => { + setFormUpdated(isDirty) + }, [isDirty, setFormUpdated]) + + return ( + +
+
+ + {t("biography")} + + + {t("submit")} + +
+ +
+
+ ) +} + +function ReadonlyBiography({ profile }: { profile: Profile }) { + const { about }: Profile = profile + const { t } = useTranslation("legislators") + + return ( + + {t("biography")} +
+ {about ? about : t("notClaimed")} +
+
+ ) } diff --git a/components/legislator/SidebarComponents/LegislatorSidebar.tsx b/components/legislator/SidebarComponents/LegislatorSidebar.tsx index 39f77168e..e9ca0994a 100644 --- a/components/legislator/SidebarComponents/LegislatorSidebar.tsx +++ b/components/legislator/SidebarComponents/LegislatorSidebar.tsx @@ -1,14 +1,20 @@ +import { Profile } from "../../db" import { Biography } from "./Biography" import { OtherTestimony } from "./OtherTestimony" import { UpcomingHearings } from "./UpcomingHearings" -export function LegislatorSidebar() { +export function LegislatorSidebar({ + pageId, + publicProfile +}: { + pageId: string + publicProfile: Profile | undefined +}) { return ( <> - Sidebar Components - + ) } diff --git a/public/locales/en/legislators.json b/public/locales/en/legislators.json index fecb79040..a3f05ec4a 100644 --- a/public/locales/en/legislators.json +++ b/public/locales/en/legislators.json @@ -1,11 +1,15 @@ { + "addBio": "Add your biography", "billsSponsored": "Bills Sponsored", + "biography": "Biography", "canSubmit": "can submit testimony on any bill or ballot question, just like any constituent. Her stance and reasoning are shown exactly as submitted — MAPLE does not edit or editorialize.", "contact": "Contact", "cosponsored": "Cosponsored", + "editBio": "Edit your biography", "fundsRaised": "Funds Raised", "home": "Home", "legislators": "Legislators", + "notClaimed": "This legislator has not claimed their MAPLE account", "party": { "democratic": "Democratic Party", "party": "Party", @@ -13,6 +17,7 @@ }, "stateRepresentative": "State Representative", "stateSenator": "State Senator", + "submit": "Submit", "tabs": { "bills": "Bills", "district": "District",