-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: find and manage friends, optimize source code
- Loading branch information
Showing
10 changed files
with
230 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
<script setup lang="ts"> | ||
import { storeToRefs } from 'pinia'; | ||
import Image from 'primevue/image'; | ||
import type { PropType } from 'vue'; | ||
import { onMounted, ref } from 'vue'; | ||
import { Attachment, Post } from '@/database'; | ||
import { useUser } from '@/stores/user'; | ||
import type { IAttachmentItem, IUser } from '@/types'; | ||
import CreatePostBox from '../Common/CreatePostBox.vue'; | ||
import PostList from '../Post/PostList.vue'; | ||
const props = defineProps({ | ||
user: { | ||
type: Object as PropType<IUser>, | ||
required: true | ||
} | ||
}) | ||
const { cuser } = storeToRefs(useUser()) | ||
const images = ref<{ id: number, image: string }[]>([]) | ||
onMounted(async () => { | ||
const posts = await Post.getAll({ | ||
uid: props.user.id, | ||
limit: 20, | ||
sort: 'created_at', | ||
order: 'desc', | ||
attachment: true | ||
}) | ||
for (const post of posts) { | ||
if (post.attachment) { | ||
const medium = await Attachment.image((post.attachment as IAttachmentItem).large) | ||
if (images.value.length === 9) break; | ||
else images.value.push({ id: post.id, image: medium }) | ||
} | ||
} | ||
}) | ||
</script> | ||
<template> | ||
<div class="w-full md:w-5/12 mt-4 mr-4"> | ||
<div class="bg-white p-3 rounded-lg shadow-lg"> | ||
<div class="font-bold pb-2 text-xl">Giới thiệu</div> | ||
<div class="pb-5"> | ||
<button class="w-full bg-gray-200 hover:bg-gray-300 rounded-lg p-2 font-medium text-sm text-[#050505]"> | ||
Thêm tiểu sử | ||
</button> | ||
</div> | ||
<div class="pb-5"> | ||
<button class="w-full bg-gray-200 hover:bg-gray-300 rounded-lg p-2 font-medium text-sm text-[#050505]"> | ||
Chỉnh sửa chi tiết | ||
</button> | ||
</div> | ||
<div class="pb-5"> | ||
<button class="w-full bg-gray-200 hover:bg-gray-300 rounded-lg p-2 font-medium text-sm text-[#050505]"> | ||
Chỉnh sửa sở thích | ||
</button> | ||
</div> | ||
<div> | ||
<button class="w-full bg-gray-200 hover:bg-gray-300 rounded-lg p-2 font-medium text-sm text-[#050505]"> | ||
Thêm nội dung đáng chú ý | ||
</button> | ||
</div> | ||
</div> | ||
|
||
<div class="bg-white p-3 mt-4 rounded-lg shadow-lg sticky z-10 top-20"> | ||
<div class="font-bold pb-2 text-xl">Ảnh</div> | ||
<div class="grid grid-cols-3"> | ||
<router-link :to="{ name: 'post', params: { id: i.id } }" v-for="i in images" :key="i.id" class="rounded-lg"> | ||
<Image :src="i.image" :pt="{ | ||
root: 'rounded-lg relative', | ||
image: { | ||
class: 'cursor-pointer border-white border-4 border-white aspect-square object-cover rounded-lg cursor-pointer' | ||
} | ||
}" /> | ||
</router-link> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<div class="w-full md:w-7/12 overflow-y-scroll overflow-x-hidden nice-scrollbar" v-if="cuser"> | ||
<CreatePostBox v-if="cuser.id === props.user.id" /> | ||
<PostList scope="user" :uid="props.user.id" :avatar="props.user?.photoURL" /> | ||
</div> | ||
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export function protectEmail(email: string, char = '*') { | ||
const [name, domain] = email.split('@') | ||
const protectedEmail = `${name.slice(0, 3)}${char.repeat(name.length - 4)}@${domain}` | ||
return protectedEmail | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
<script setup lang="ts"> | ||
import { debounce } from 'lodash'; | ||
import Avatar from 'primevue/avatar'; | ||
import Button from 'primevue/button'; | ||
import { computed, onMounted, ref, watch } from 'vue'; | ||
import { useRouter } from 'vue-router'; | ||
import { Attachment, Friend, User } from '@/database'; | ||
import { protectEmail } from '@/helpers/protected'; | ||
import type { IUser } from '@/types'; | ||
const router = useRouter() | ||
const search = ref<string>(''); | ||
const friends = ref<IUser[]>([]) | ||
const fsearch = ref<IUser[]>([]) | ||
const hasFriendSearch = computed(() => { | ||
return fsearch.value.length > 0 | ||
}) | ||
async function loadFriends() { | ||
const id = router.currentRoute.value.params.id | ||
const f = await Friend.getByUID(parseInt(id as string)) | ||
const users = await User.getAll() | ||
if (f && users.length > 0) { | ||
for (const user of users) { | ||
if (f.friends.includes(user.id.toString())) { | ||
if (Attachment.isID(user.photoURL)) { | ||
const attachment = await Attachment.get(user.photoURL) | ||
user.photoURL = await Attachment.image(attachment.attachments.large) | ||
friends.value.push(user) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
onMounted(async () => { | ||
await loadFriends() | ||
fsearch.value = friends.value | ||
}) | ||
watch(search, debounce(async (value) => { | ||
if (value === '') fsearch.value = friends.value | ||
else { | ||
fsearch.value = friends.value.filter((item) => { | ||
return item.displayName.toLowerCase().includes(value.toLowerCase()) | ||
}) | ||
} | ||
}, 500)) | ||
</script> | ||
<template> | ||
<div class="w-full h-full rounded-lg bg-white my-4 p-5"> | ||
<div class="flex flex-row items-center justify-between"> | ||
<div class="select-none px-2"> | ||
<span class="text-xl font-medium">Bạn bè</span> | ||
</div> | ||
<div class="flex flex-row space-x-3"> | ||
<div class="flex bg-[#EFF2F5] items-center justify-start w-full rounded-full cursor-pointer py-2"> | ||
<i class="pi pi-search pl-3 mx-auto text-[#64676B] text-lg" /> | ||
<input type="text" placeholder="Tìm kiếm bạn bè" v-model="search" | ||
class="outline-none border-none h-3 bg-transparent w-full inline-block px-3 py-3" /> | ||
</div> | ||
<div class="w-full"> | ||
<router-link :to="{ name: 'friends' }"> | ||
<Button label="Lời mời kết bạn" text size="small" /> | ||
</router-link> | ||
<router-link :to="{ name: 'friends' }"> | ||
<Button label="Tìm bạn bè" text size="small" /> | ||
</router-link> | ||
</div> | ||
</div> | ||
</div> | ||
<div class="grid grid-cols-1 md:grid-cols-2 h-full w-full gap-3 my-5" v-if="hasFriendSearch"> | ||
<div class="h-[100px] w-full rounded-md border" v-for="(item, index) in fsearch" :key="index"> | ||
<router-link :to="{ name: 'user', params: { id: item.id } }"> | ||
<div | ||
class="flex flex-row items-center justify-start w-full h-full rounded-md cursor-pointer hover:bg-[#EFF2F5] transition-all space-x-5 px-5"> | ||
<div class="cursor-pointer"> | ||
<Avatar :image="item.photoURL" size="xlarge" :pt="{ | ||
root: 'w-16 h-16', | ||
image: 'rounded-lg w-full h-full' | ||
}" /> | ||
</div> | ||
<div class="flex flex-col w-full space-y-1"> | ||
<span class="text-[#050505] text-lg font-medium truncate">{{ item.displayName }}</span> | ||
<span class="text-[#050505] text-md font-medium truncate">{{ protectEmail(item.email, '*') }}</span> | ||
</div> | ||
</div> | ||
</router-link> | ||
</div> | ||
</div> | ||
<div class="flex flex-col items-center justify-center w-full h-full py-5" v-else> | ||
<span class="text-lg font-medium">Không có kết quả cho: {{ search }}</span> | ||
</div> | ||
</div> | ||
</template> |
Oops, something went wrong.