mirror of
https://github.com/CompassConnections/Compass.git
synced 2026-04-14 11:38:31 -04:00
Add option to save / bookmark profiles
This commit is contained in:
@@ -10,13 +10,14 @@ import {Select} from 'web/components/widgets/select'
|
||||
import {DesktopFilters} from './desktop-filters'
|
||||
import {LocationFilterProps} from './location-filter'
|
||||
import {MobileFilters} from './mobile-filters'
|
||||
import {BookmarkSearchButton} from "web/components/searches/button";
|
||||
import {BookmarkSearchButton, BookmarkStarButton} from "web/components/searches/button";
|
||||
import {BookmarkedSearchesType} from "web/hooks/use-bookmarked-searches";
|
||||
import {submitBookmarkedSearch} from "web/lib/supabase/searches";
|
||||
import {useUser} from "web/hooks/use-user";
|
||||
import {isEqual} from "lodash";
|
||||
import toast from "react-hot-toast";
|
||||
import {FilterFields, initialFilters} from "common/filters";
|
||||
import {DisplayUser} from "common/api/user-types";
|
||||
|
||||
function isOrderBy(input: string): input is FilterFields['orderBy'] {
|
||||
return ['last_online_time', 'created_time', 'compatibility_score'].includes(
|
||||
@@ -96,7 +97,8 @@ function getRandomPair(count = 3): string {
|
||||
const MAX_BOOKMARKED_SEARCHES = 10;
|
||||
export const Search = (props: {
|
||||
youProfile: Profile | undefined | null
|
||||
starredUserIds: string[]
|
||||
starredUsers: DisplayUser[]
|
||||
refreshStars: () => void
|
||||
// filter props
|
||||
filters: Partial<FilterFields>
|
||||
updateFilter: (newState: Partial<FilterFields>) => void
|
||||
@@ -117,6 +119,8 @@ export const Search = (props: {
|
||||
filters,
|
||||
bookmarkedSearches,
|
||||
refreshBookmarkedSearches,
|
||||
starredUsers,
|
||||
refreshStars,
|
||||
} = props
|
||||
|
||||
const [openFiltersModal, setOpenFiltersModal] = useState(false)
|
||||
@@ -128,6 +132,7 @@ export const Search = (props: {
|
||||
const [bookmarked, setBookmarked] = useState(false);
|
||||
const [loadingBookmark, setLoadingBookmark] = useState(false);
|
||||
const [openBookmarks, setOpenBookmarks] = useState(false);
|
||||
const [openStarBookmarks, setOpenStarBookmarks] = useState(false);
|
||||
const user = useUser()
|
||||
|
||||
useEffect(() => {
|
||||
@@ -254,7 +259,7 @@ export const Search = (props: {
|
||||
color={'none'}
|
||||
className={'bg-canvas-100 hover:bg-canvas-200'}
|
||||
>
|
||||
{bookmarked ? 'Bookmarked!' : loadingBookmark ? '' : 'Get Notified'}
|
||||
{bookmarked ? 'Saved!' : loadingBookmark ? '' : 'Get Notified'}
|
||||
</Button>
|
||||
|
||||
<BookmarkSearchButton
|
||||
@@ -263,6 +268,16 @@ export const Search = (props: {
|
||||
open={openBookmarks}
|
||||
setOpen={setOpenBookmarks}
|
||||
/>
|
||||
|
||||
<BookmarkStarButton
|
||||
refreshStars={refreshStars}
|
||||
starredUsers={starredUsers}
|
||||
open={openStarBookmarks}
|
||||
setOpen={(checked) => {
|
||||
setOpenStarBookmarks(checked)
|
||||
refreshStars()
|
||||
}}
|
||||
/>
|
||||
</Row>
|
||||
</Col>
|
||||
)
|
||||
|
||||
@@ -66,7 +66,7 @@ export const ProfileGrid = (props: {
|
||||
{!isLoadingMore && !isReloading && other_profiles.length === 0 && (
|
||||
<div className="py-8 text-center">
|
||||
<p>No profiles found.</p>
|
||||
<p>Feel free to click on Get Notified and we'll notify you when new users match it!</p>
|
||||
<p>Feel free to click on Get Notified and we'll notify you when new users match your search!</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -22,6 +22,7 @@ import {useState} from 'react'
|
||||
import {VisibilityConfirmationModal} from './visibility-confirmation-modal'
|
||||
import {deleteAccount} from "web/lib/util/delete";
|
||||
import toast from "react-hot-toast";
|
||||
import {StarButton} from "web/components/widgets/star-button";
|
||||
|
||||
export default function ProfileHeader(props: {
|
||||
user: User
|
||||
@@ -38,8 +39,8 @@ export default function ProfileHeader(props: {
|
||||
profile,
|
||||
userActivity,
|
||||
simpleView,
|
||||
// starredUserIds,
|
||||
// refreshStars,
|
||||
starredUserIds,
|
||||
refreshStars,
|
||||
showMessageButton,
|
||||
refreshProfile,
|
||||
} = props
|
||||
@@ -145,13 +146,13 @@ export default function ProfileHeader(props: {
|
||||
className="sm:flex"
|
||||
username={user.username}
|
||||
/>
|
||||
{/*{currentUser && (*/}
|
||||
{/* <StarButton*/}
|
||||
{/* targetProfile={profile}*/}
|
||||
{/* isStarred={starredUserIds.includes(user.id)}*/}
|
||||
{/* refresh={refreshStars}*/}
|
||||
{/* />*/}
|
||||
{/*)}*/}
|
||||
{currentUser && (
|
||||
<StarButton
|
||||
targetProfile={profile}
|
||||
isStarred={starredUserIds.includes(user.id)}
|
||||
refresh={refreshStars}
|
||||
/>
|
||||
)}
|
||||
{currentUser && showMessageButton && (
|
||||
<SendMessageButton toUser={user} currentUser={currentUser}/>
|
||||
)}
|
||||
|
||||
@@ -31,11 +31,12 @@ export function ProfileInfo(props: {
|
||||
// const currentProfile = useProfile()
|
||||
// const isCurrentUser = currentUser?.id === user.id
|
||||
|
||||
const {data: starredUserIds, refresh: refreshStars} = useGetter(
|
||||
const {data: starredUsers, refresh: refreshStars} = useGetter(
|
||||
'stars',
|
||||
currentUser?.id,
|
||||
getStars
|
||||
)
|
||||
const starredUserIds = starredUsers?.map((u) => u.id)
|
||||
|
||||
// const { data, refresh } = useAPIGetter('get-likes-and-ships', {
|
||||
// userId: user.id,
|
||||
|
||||
@@ -13,7 +13,6 @@ import {usePersistentInMemoryState} from 'web/hooks/use-persistent-in-memory-sta
|
||||
import {useUser} from 'web/hooks/use-user'
|
||||
import {api} from 'web/lib/api'
|
||||
import {useBookmarkedSearches} from "web/hooks/use-bookmarked-searches";
|
||||
import {orderProfiles} from "common/filters";
|
||||
import {useFilters} from "web/components/filters/use-filters";
|
||||
|
||||
export function ProfilesHome() {
|
||||
@@ -64,9 +63,12 @@ export function ProfilesHome() {
|
||||
});
|
||||
}, [filters]);
|
||||
|
||||
const {data: starredUserIds, refresh: refreshStars} = useGetter('star', user?.id, getStars);
|
||||
const compatibleProfiles = useCompatibleProfiles(user?.id);
|
||||
const displayProfiles = profiles && orderProfiles(profiles, starredUserIds);
|
||||
const {data: starredUsers, refresh: refreshStars} = useGetter('star', user?.id, getStars)
|
||||
const starredUserIds = starredUsers?.map((u) => u.id)
|
||||
|
||||
const compatibleProfiles = useCompatibleProfiles(user?.id)
|
||||
// const displayProfiles = profiles && orderProfiles(profiles, starredUserIds);
|
||||
const displayProfiles = profiles
|
||||
|
||||
const loadMore = useCallback(async () => {
|
||||
if (!profiles || isLoadingMore) return false;
|
||||
@@ -96,7 +98,8 @@ export function ProfilesHome() {
|
||||
<Title className="!mb-2 text-3xl">Profiles</Title>
|
||||
<Search
|
||||
youProfile={you}
|
||||
starredUserIds={starredUserIds ?? []}
|
||||
starredUsers={starredUsers ?? []}
|
||||
refreshStars={refreshStars}
|
||||
filters={filters}
|
||||
updateFilter={updateFilter}
|
||||
clearFilters={clearFilters}
|
||||
|
||||
@@ -7,6 +7,10 @@ import {useUser} from "web/hooks/use-user";
|
||||
import {deleteBookmarkedSearch} from "web/lib/supabase/searches";
|
||||
import {formatFilters, locationType} from "common/searches";
|
||||
import {FilterFields} from "common/filters";
|
||||
import {api} from "web/lib/api";
|
||||
import {DisplayUser} from "common/api/user-types";
|
||||
import {Link} from "@react-email/components";
|
||||
import {DOMAIN} from "common/envs/constants";
|
||||
|
||||
export function BookmarkSearchButton(props: {
|
||||
bookmarkedSearches: BookmarkedSearchesType[]
|
||||
@@ -26,7 +30,7 @@ export function BookmarkSearchButton(props: {
|
||||
return (
|
||||
<>
|
||||
<Button onClick={() => setOpen(true)} color="gray-outline" size={'xs'}>
|
||||
My Bookmarked Searches
|
||||
Saved Searches
|
||||
</Button>
|
||||
<ButtonModal
|
||||
open={open}
|
||||
@@ -57,11 +61,12 @@ function ButtonModal(props: {
|
||||
}}
|
||||
>
|
||||
<Col className={MODAL_CLASS}>
|
||||
<h3>Bookmarked Searches</h3>
|
||||
<p className='text-sm'>We'll notify you daily when new people match your searches below.</p>
|
||||
<h3>Saved Searches</h3>
|
||||
{bookmarkedSearches?.length ? (<>
|
||||
<p>We'll notify you daily when new people match your searches below.</p>
|
||||
<Col
|
||||
className={
|
||||
'border-ink-300bg-canvas-0 inline-flex flex-col gap-2 rounded-md border p-1 text-sm shadow-sm'
|
||||
'border-ink-300bg-canvas-0 inline-flex flex-col gap-2 rounded-md border p-1 shadow-sm'
|
||||
}
|
||||
>
|
||||
<ol className="list-decimal list-inside space-y-2">
|
||||
@@ -83,6 +88,116 @@ function ButtonModal(props: {
|
||||
</ol>
|
||||
|
||||
</Col>
|
||||
</>
|
||||
) : <p>You haven't saved any search. To save one, click on Get Notified and we'll notify you daily when new people match it.</p>}
|
||||
{/*<BookmarkSearchContent*/}
|
||||
{/* total={bookmarkedSearches.length}*/}
|
||||
{/* compatibilityQuestion={bookmarkedSearches[questionIndex]}*/}
|
||||
{/* user={user}*/}
|
||||
{/* onSubmit={() => {*/}
|
||||
{/* setOpen(false)*/}
|
||||
{/* }}*/}
|
||||
{/* isLastQuestion={questionIndex === bookmarkedSearches.length - 1}*/}
|
||||
{/* onNext={() => {*/}
|
||||
{/* if (questionIndex === bookmarkedSearches.length - 1) {*/}
|
||||
{/* setOpen(false)*/}
|
||||
{/* } else {*/}
|
||||
{/* setQuestionIndex(questionIndex + 1)*/}
|
||||
{/* }*/}
|
||||
{/* }}*/}
|
||||
{/*/>*/}
|
||||
</Col>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export function BookmarkStarButton(props: {
|
||||
starredUsers: DisplayUser[]
|
||||
refreshStars: () => void
|
||||
open: boolean
|
||||
setOpen: (checked: boolean) => void
|
||||
}) {
|
||||
const {
|
||||
starredUsers,
|
||||
refreshStars,
|
||||
open,
|
||||
setOpen,
|
||||
} = props
|
||||
const user = useUser()
|
||||
|
||||
if (!user) return null
|
||||
return (
|
||||
<>
|
||||
<Button onClick={() => setOpen(true)} color="gray-outline" size={'xs'}>
|
||||
Saved Profiles
|
||||
</Button>
|
||||
<StarModal
|
||||
open={open}
|
||||
setOpen={setOpen}
|
||||
user={user}
|
||||
starredUsers={starredUsers}
|
||||
refreshStars={refreshStars}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
function StarModal(props: {
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
user: User
|
||||
starredUsers: DisplayUser[]
|
||||
refreshStars: () => void
|
||||
}) {
|
||||
const {open, setOpen, starredUsers, refreshStars} = props
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={open}
|
||||
setOpen={setOpen}
|
||||
// onClose={() => {
|
||||
// refreshBookmarkedSearches()
|
||||
// }}
|
||||
>
|
||||
<Col className={MODAL_CLASS}>
|
||||
<h3>Saved Profiles</h3>
|
||||
{starredUsers?.length ? (<>
|
||||
<p>Here are the profiles you saved:</p>
|
||||
<Col
|
||||
className={
|
||||
'border-ink-300bg-canvas-0 inline-flex flex-col gap-2 rounded-md border p-1 shadow-sm'
|
||||
}
|
||||
>
|
||||
<ol className="list-decimal list-inside space-y-2">
|
||||
{(starredUsers || []).map((user) => (
|
||||
<li key={user.id}
|
||||
className="items-center justify-between gap-2 list-item marker:text-ink-500 marker:font-bold">
|
||||
{user.name} (<Link
|
||||
href={`https://${DOMAIN}/${user.username}`}
|
||||
// style={{color: "#2563eb", textDecoration: "none"}}
|
||||
>
|
||||
@{user.username}
|
||||
</Link>) {' '}
|
||||
<button
|
||||
onClick={async () => {
|
||||
await api('star-profile', {
|
||||
targetUserId: user.id,
|
||||
remove: true,
|
||||
})
|
||||
refreshStars()
|
||||
}}
|
||||
className="inline-flex text-xl h-5 w-5 items-center justify-center rounded-full text-red-600 hover:bg-red-200 focus:outline-none focus:ring-2 focus:ring-red-400"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
|
||||
</Col>
|
||||
</>
|
||||
) : <p>You haven't saved any profile. To save one, click on the star on their profile page.</p>}
|
||||
{/*<BookmarkSearchContent*/}
|
||||
{/* total={bookmarkedSearches.length}*/}
|
||||
{/* compatibilityQuestion={bookmarkedSearches[questionIndex]}*/}
|
||||
|
||||
@@ -52,7 +52,7 @@ export const StarButton = (props: {
|
||||
>
|
||||
<StarIcon
|
||||
className={clsx(
|
||||
'h-10 w-10 transition-colors group-hover:fill-yellow-400/70',
|
||||
'h-8 w-8 transition-colors group-hover:fill-yellow-400/70',
|
||||
isStarred &&
|
||||
'fill-yellow-400 stroke-yellow-500 dark:stroke-yellow-600'
|
||||
)}
|
||||
@@ -63,7 +63,7 @@ export const StarButton = (props: {
|
||||
if (hideTooltip) return button
|
||||
|
||||
return (
|
||||
<Tooltip text={isStarred ? 'Remove star' : 'Add star'} noTap>
|
||||
<Tooltip text={isStarred ? 'Unsave Profile' : 'Save Profile'} noTap>
|
||||
{button}
|
||||
</Tooltip>
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { run } from 'common/supabase/utils'
|
||||
import { db } from 'web/lib/supabase/db'
|
||||
import {DisplayUser} from "common/api/user-types";
|
||||
|
||||
export const getStars = async (creatorId: string) => {
|
||||
const { data } = await run(
|
||||
@@ -12,5 +13,13 @@ export const getStars = async (creatorId: string) => {
|
||||
|
||||
if (!data) return []
|
||||
|
||||
return data.map((d) => d.target_id as string)
|
||||
const ids = data.map((d) => d.target_id as string)
|
||||
const {data: users} = await run(
|
||||
db
|
||||
.from('users')
|
||||
.select(`id, name, username`)
|
||||
.in('id', ids)
|
||||
)
|
||||
|
||||
return users as unknown as DisplayUser[]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user