From fcf802b7e34969b746935e996f03c118fc8f2452 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Thu, 9 Oct 2025 21:51:08 +0200 Subject: [PATCH] Refactor bios and add character counter --- common/src/constants.ts | 2 + web/components/bio/editable-bio.tsx | 118 ++++++++++++++++------------ 2 files changed, 68 insertions(+), 52 deletions(-) diff --git a/common/src/constants.ts b/common/src/constants.ts index 9bab04a5..3f54ca89 100644 --- a/common/src/constants.ts +++ b/common/src/constants.ts @@ -18,3 +18,5 @@ export const formLink = "https://forms.gle/tKnXUMAbEreMK6FC6" export const pStyle = "mt-1 text-gray-800 dark:text-white whitespace-pre-line"; export const IS_MAINTENANCE = false; // set to true to enable maintenance mode banner + +export const MIN_BIO_LENGTH = 300; diff --git a/web/components/bio/editable-bio.tsx b/web/components/bio/editable-bio.tsx index 45eaf470..ca02adb4 100644 --- a/web/components/bio/editable-bio.tsx +++ b/web/components/bio/editable-bio.tsx @@ -1,16 +1,17 @@ -import { JSONContent } from '@tiptap/core' -import { MAX_DESCRIPTION_LENGTH } from 'common/envs/constants' -import { Profile } from 'common/love/profile' -import { tryCatch } from 'common/util/try-catch' -import { Button } from 'web/components/buttons/button' -import { Col } from 'web/components/layout/col' -import { Row } from 'web/components/layout/row' -import { TextEditor, useTextEditor } from 'web/components/widgets/editor' -import { updateProfile } from 'web/lib/api' -import { track } from 'web/lib/service/analytics' -import React, {useState} from "react"; +import {JSONContent} from '@tiptap/core' +import {MAX_DESCRIPTION_LENGTH} from 'common/envs/constants' +import {Profile} from 'common/love/profile' +import {tryCatch} from 'common/util/try-catch' +import {Button} from 'web/components/buttons/button' +import {Col} from 'web/components/layout/col' +import {Row} from 'web/components/layout/row' +import {TextEditor, useTextEditor} from 'web/components/widgets/editor' +import {updateProfile} from 'web/lib/api' +import {track} from 'web/lib/service/analytics' +import React, {useEffect, useState} from "react"; import ReactMarkdown from "react-markdown"; import Link from "next/link" +import {MIN_BIO_LENGTH} from "common/constants"; const placeHolder = "Tell us about yourself — and what you're looking for!"; @@ -23,10 +24,6 @@ Write a clear and engaging bio to help others understand who you are and the con - Optional: romantic preferences, lifestyle habits, and conversation starters ` -export function CharLimitText() { - return

Profiles with fewer than 250 characters will be hidden by default from the profile grid — write a meaningful bio so others can find you through keyword search and connect intentionally.

-} - export function BioTips() { const [showMoreInfo, setShowMoreInfo] = useState(false) @@ -62,18 +59,15 @@ export function EditableBio(props: { onSave: () => void onCancel?: () => void }) { - const { profile, onCancel, onSave } = props - const editor = useTextEditor({ - max: MAX_DESCRIPTION_LENGTH, - defaultValue: (profile.bio as JSONContent) ?? '', - placeholder: placeHolder, - }) + const {profile, onCancel, onSave} = props + const [editor, setEditor] = useState(null) + const [textLength, setTextLength] = useState(0); - const hideButtons = editor?.getText().length === 0 && !profile.bio + const hideButtons = (textLength === 0) && !profile.bio const saveBio = async () => { if (!editor) return - const { error } = await tryCatch(updateProfile({ bio: editor.getJSON() })) + const {error} = await tryCatch(updateProfile({bio: editor.getJSON()})) if (error) { console.error(error) @@ -85,10 +79,15 @@ export function EditableBio(props: { return ( - - - - + { + setEditor(e); + e?.on('update', () => { + setTextLength(e.getText().length); + }); + }} + /> {!hideButtons && ( {onCancel && ( @@ -114,38 +113,53 @@ export function EditableBio(props: { export function SignupBio(props: { onChange: (e: JSONContent) => void }) { - const { onChange } = props - const editor = useTextEditor({ - max: MAX_DESCRIPTION_LENGTH, - defaultValue: '', - placeholder: placeHolder, - }) - - // const [charLength, setCharLength] = useState(0) - + const {onChange} = props return ( - - - { - // console.debug('onchange', editor?.getText()) + { if (!editor) return const e = editor.getJSON() - // console.debug(e) - // const text = e.content.map((block: any) => block.content?.map((c: any) => c.text).join('') ?? '').join(''); - // setCharLength(text.length) - // console.debug(text, text.length) - // if (text.length < 250) { - // return; // do not save - // } - - // console.debug('bio changed', e, profile.bio); onChange(e) }} /> - {/*

{charLength} / 250

*/} ) } + +interface BaseBioProps { + defaultValue?: any + onBlur?: (editor: any) => void + onEditor?: (editor: any) => void +} + +export function BaseBio({defaultValue, onBlur, onEditor}: BaseBioProps) { + const editor = useTextEditor({ + // extensions: [StarterKit], + max: MAX_DESCRIPTION_LENGTH, + defaultValue: defaultValue, + placeholder: placeHolder, + }) + const textLength = editor?.getText().length ?? 0 + + useEffect(() => { + onEditor?.(editor) + }, [editor, onEditor]) + + return ( +
+ {textLength < MIN_BIO_LENGTH && +

+ Write {MIN_BIO_LENGTH - textLength} more {MIN_BIO_LENGTH - textLength === 1 ? 'character' : 'characters'} so + others can find you through keyword + search and connect intentionally. +

+ } + + onBlur?.(editor)} + /> +
+ ) +}