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 (
+
+
+
+ )
+}
+
+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",