From 398737e15b8523edd00710b9279424740bef0c03 Mon Sep 17 00:00:00 2001 From: Ammar Waheed Date: Sat, 4 Jan 2025 02:49:33 +0500 Subject: [PATCH 1/8] init commit --- .prettierrc | 9 + src/app/(dashboard)/profile/[id]/page.tsx | 2 - .../Dashboard/profile/ProfileScreen.tsx | 138 ++++------ .../Dashboard/profile/edit-profile-modal.tsx | 248 +++++++++++++++--- .../profile/hooks/useUserInterests.ts | 51 ++++ .../Dashboard/profile/hooks/useUserSkills.ts | 47 ++++ .../Dashboard/profile/profile-activities.tsx | 29 +- .../Dashboard/profile/profile-bio.tsx | 179 ++++++++----- .../Dashboard/profile/profile-rewards.tsx | 27 +- .../profile/types/profile-types.d.ts | 23 ++ src/components/TagsInput/TagsInput.tsx | 165 ++++++++++++ src/components/chips-input/chips-input.css | 37 --- src/components/chips-input/index.tsx | 31 --- src/components/common/Loader/Loader.tsx | 29 +- .../common/Loader/types/loader-types.d.ts | 6 + src/db/data-access/activity/query.ts | 32 +++ src/db/data-access/recommendation/query.ts | 0 src/db/data-access/reward/query.ts | 32 +++ src/db/data-access/tag/query.ts | 56 ++++ src/db/data-access/user/query.ts | 110 ++++---- src/db/schema.ts | 246 +++++++++-------- src/server-actions/Activity/Activity.ts | 49 ++++ src/server-actions/Reward/Reward.ts | 46 ++++ src/server-actions/Tag/Tag.ts | 33 +++ src/server-actions/User/User.ts | 74 ++++++ src/store/profile/profileStore.ts | 12 + tsconfig.json | 2 +- 27 files changed, 1276 insertions(+), 437 deletions(-) create mode 100644 .prettierrc create mode 100644 src/components/Dashboard/profile/hooks/useUserInterests.ts create mode 100644 src/components/Dashboard/profile/hooks/useUserSkills.ts create mode 100644 src/components/TagsInput/TagsInput.tsx delete mode 100644 src/components/chips-input/chips-input.css delete mode 100644 src/components/chips-input/index.tsx create mode 100644 src/components/common/Loader/types/loader-types.d.ts create mode 100644 src/db/data-access/activity/query.ts create mode 100644 src/db/data-access/recommendation/query.ts create mode 100644 src/db/data-access/reward/query.ts create mode 100644 src/db/data-access/tag/query.ts create mode 100644 src/server-actions/Activity/Activity.ts create mode 100644 src/server-actions/Reward/Reward.ts create mode 100644 src/server-actions/Tag/Tag.ts create mode 100644 src/server-actions/User/User.ts create mode 100644 src/store/profile/profileStore.ts diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..2fa1304 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "trailingComma": "none", + "semi": false, + "tabWidth": 2, + "singleQuote": false, + "printWidth": 80, + "proseWrap": "preserve", + "quoteProps": "as-needed" +} diff --git a/src/app/(dashboard)/profile/[id]/page.tsx b/src/app/(dashboard)/profile/[id]/page.tsx index 7e3a036..1e611c3 100644 --- a/src/app/(dashboard)/profile/[id]/page.tsx +++ b/src/app/(dashboard)/profile/[id]/page.tsx @@ -6,14 +6,12 @@ import ProfileCalendar from "@/src/components/Dashboard/profile/profile-calendar import ProfileRewards from "@/src/components/Dashboard/profile/profile-rewards" import ProfileFollowActions from "@/src/components/Dashboard/profile/user/ProfileFollowActions" import { Avatar, AvatarFallback, AvatarImage } from "@/src/components/ui/avatar" -import { Button } from "@/src/components/ui/button" import { Tabs, TabsContent, TabsList, TabsTrigger, } from "@/src/components/ui/tabs" -import { SelectUser } from "@/src/db/schema" import { FindUserByUniqueIdAction } from "@/src/server-actions/User/FindUserByUniqueIdAction" import { CalendarIcon, StarIcon, TrophyIcon, UserIcon } from "lucide-react" import Link from "next/link" diff --git a/src/components/Dashboard/profile/ProfileScreen.tsx b/src/components/Dashboard/profile/ProfileScreen.tsx index e1e68ac..eb81fd2 100644 --- a/src/components/Dashboard/profile/ProfileScreen.tsx +++ b/src/components/Dashboard/profile/ProfileScreen.tsx @@ -1,5 +1,3 @@ -"use client" - import ProfileActivities from "@/src/components/Dashboard/profile/profile-activities" import ProfileBio from "@/src/components/Dashboard/profile/profile-bio" import ProfileCalendar from "@/src/components/Dashboard/profile/profile-calendar" @@ -12,117 +10,69 @@ import { TabsTrigger } from "@/src/components/ui/tabs" import { CalendarIcon, StarIcon, TrophyIcon, UserIcon } from "lucide-react" -import { useSearchParams } from "next/navigation" -import { useEffect, useState } from "react" -import { Recommendation } from "@/src/components/Dashboard/profile/types/profile-types" -import { useUser } from "@clerk/nextjs" +import { AuthUserAction } from "@/src/server-actions/User/AuthUserAction" +import NotFound from "@/src/components/Dashboard/NotFound/NotFound" +import Link from "next/link" -const rewards = [ - { - title: "Top Contributor", - description: "Awarded for outstanding contributions to the team" - }, - { - title: "Innovation Champion", - description: "Recognized for implementing creative solutions" - } -] -const activities = [ - { - date: "2023-04-01", - description: "Completed the 'Advanced React Patterns' course" - }, - { - date: "2023-03-15", - description: "Contributed to open-source project 'awesome-ui-components'" - } -] +type ProfileScreenProps = { tab?: string } -export default function ProfileScreen() { - const searchParams = useSearchParams() - const [activeTab, setActiveTab] = useState("basic") - const [skillTags, setSkillTags] = useState([ - "Web Development", - "AI", - "Open Source", - "Tech Writing" - ]) - const [interests, setInterests] = useState([ - "React", - "Next.js", - "TypeScript", - "UI/UX", - "Node.js" - ]) - const [recommendations, setRecommendations] = useState([ - { - name: "Jane Doe", - text: "An exceptional developer with a keen eye for detail." - }, - { name: "John Smith", text: "Always delivers high-quality work on time." } - ]) - const { user } = useUser() +export default async function ProfileScreen({ tab }: ProfileScreenProps) { + const user = await AuthUserAction() - useEffect(() => { - const tab = searchParams.get("tab") - if (tab) { - setActiveTab(tab) - } - }, [searchParams]) + if (!user) { + return + } return (
- - JD + + Profile Image
-

{user?.fullName}

-

- {user?.emailAddresses[0].emailAddress} -

+

{user?.first_name}

+

{user?.email}

- + - setActiveTab("basic")}> - - Bio/Basic - - setActiveTab("rewards")}> - - Rewards - - setActiveTab("activity")} - > - - Activity - - setActiveTab("calendar")} - > - - Calendar - + + + + Bio/Basic + + + + + + Rewards + + + + + + Activity + + + + + + Calendar + + - + - + - + diff --git a/src/components/Dashboard/profile/edit-profile-modal.tsx b/src/components/Dashboard/profile/edit-profile-modal.tsx index 71232d6..fb6456e 100644 --- a/src/components/Dashboard/profile/edit-profile-modal.tsx +++ b/src/components/Dashboard/profile/edit-profile-modal.tsx @@ -1,4 +1,4 @@ -import { useRef, useState } from "react" +import { useEffect, useState } from "react" import { Button } from "../../ui/button" import { Dialog, @@ -9,34 +9,150 @@ import { DialogTitle, DialogTrigger } from "../../ui/dialog" -import { Input } from "../../ui/input" import { Label } from "../../ui/label" import { Textarea } from "@/src/components/ui/textarea" -import ChipsInput from "@/src/components/chips-input" +import TagsInput from "@/src/components/TagsInput/TagsInput" +import { SaveUserProfileAction } from "@/src/server-actions/User/User" +import { useServerAction } from "@/src/hooks/useServerAction" +import { useAtomValue, useSetAtom } from "jotai" +import { userStore } from "@/src/store/user/userStore" +import { profileStore } from "@/src/store/profile/profileStore" +import useUserSkills from "./hooks/useUserSkills" +import useUserInterests from "./hooks/useUserInterests" +import { ProfileData, Tag, TagStatus } from "./types/profile-types.d" +import { useToast } from "@/src/hooks/use-toast" -type EditProfileModalProps = { - bio: string - setBio: (value: string) => void - interests: string[] - setInterests: (value: string[]) => void - skills: string[] - setSkills: (value: string[]) => void -} +const EditProfileModal: React.FC = () => { + const bio = useAtomValue(profileStore.bio) + const user = useAtomValue(userStore.AuthUser) + const setBio = useSetAtom(profileStore.bio) + const { toast } = useToast() + + const [isOpen, setIsOpen] = useState(false) + const [editedBio, setEditedBio] = useState(bio) + + const [ + updateProfileLoading, + updatedProfileData, + updateProfileError, + updateProfile + ] = useServerAction(SaveUserProfileAction) + + const [ + skills, + setSkills, + skillSuggestions, + searchSkills, + searchSkillsLoading + ] = useUserSkills() + + const [ + interests, + setInterests, + interestSuggestions, + searchInterests, + searchInterestsLoading + ] = useUserInterests() + + useEffect(() => { + if (updateProfileError) { + toast({ + variant: "destructive", + title: "Error updating profile", + description: "Something went wrong. Please try again.", + duration: 3000 + }) + } + }, [updateProfileError]) -const EditProfileModal: React.FC = ({setBio, setSkills, setInterests,skills, bio, interests }) => { - const [isOpen, setIsOpen] = useState(false) - const [skillsCopy, setSkillsCopy] = useState([...skills]) - const [interestsCopy, setinterestsCopy] = useState([ - ...interests - ]) - const editedBio = useRef(bio) + const updatedSkillsLength: number = skills.filter( + (tag) => !tag.deleted + ).length + const updatedInterestsLength: number = interests.filter( + (tag) => !tag.deleted + ).length + const skillsError: string = + updatedSkillsLength > 20 ? "You can only add a maximum of 20 skills" : "" + const interestsError: string = + updatedInterestsLength > 20 + ? "You can only add a maximum of 20 interests" + : "" + const bioError: string = + editedBio && editedBio?.length > 2000 + ? "Bio cannot exceed 2000 characters" + : "" - const updateProfileValue = (e: React.FormEvent) => { + const saveProfileChanges = async (e: React.FormEvent) => { e.preventDefault() - setBio(editedBio.current) - setSkills([...skillsCopy]) - setInterests([...interestsCopy]) - setIsOpen(false) + try { + const deletedSkillsIds: number[] = skills + .filter((skill) => skill.deleted && skill.status === TagStatus[1]) + .map((skill) => skill.id as number) + const deletedInterestsIds: number[] = interests + .filter( + (interest) => interest.deleted && interest.status === TagStatus[1] + ) + .map((interest) => interest.id as number) + const updatedProfileData: ProfileData = { + userId: user?.external_auth_id as string, + bio: editedBio ? editedBio : bio, + newTags: [ + ...skills + .filter((tag) => tag.status === TagStatus[3]) + .map((tag) => { + return { name: tag.name, type: "skill" } + }), + ...interests + .filter((tag) => tag.status === TagStatus[3]) + .map((tag) => { + return { name: tag.name, type: "interest" } + }) + ], + existingTags: [ + ...skills + .filter((tag) => tag.status === TagStatus[2]) + .map((tag) => { + return { name: tag.name, id: tag.id, type: "skill" } + }), + ...interests + .filter((tag) => tag.status === TagStatus[2]) + .map((tag) => { + return { name: tag.name, id: tag.id, type: "interest" } + }) + ], + deletedTagsIds: [...deletedSkillsIds, ...deletedInterestsIds] + } + await updateProfile(updatedProfileData) + // remove deleted skills + setSkills((skills: Tag[]) => + skills.filter( + (tag) => !deletedSkillsIds.includes(tag.id as number) && !tag.deleted + ) + ) + // remove deleted Interests + setInterests((interests: Tag[]) => + interests.filter( + (tag) => + !deletedInterestsIds.includes(tag.id as number) && !tag.deleted + ) + ) + editedBio && setBio(editedBio) + setIsOpen(false) + setEditedBio("") + toast({ + title: "Profile updated", + description: "Your changes have been saved successfully.", + duration: 3000 + }) + } catch (error) { + toast({ + variant: "destructive", + title: "Error updating profile", + description: + error instanceof Error ? error.message : "Something went wrong", + duration: 3000 + }) + } } return ( @@ -53,7 +169,7 @@ const EditProfileModal: React.FC = ({setBio, setSkills, s Make changes to your profile here. Click save when you're done. -
+
@@ -64,35 +180,95 @@ const EditProfileModal: React.FC = ({setBio, setSkills, s id={"bio"} defaultValue={bio} className="min-h-[100px] w-full" - onChange={(e: React.ChangeEvent) => - (editedBio.current = e.target.value) - } + onChange={(e) => setEditedBio(e.target.value)} /> +
+

2000 + ? "text-red-500" + : "text-gray-500" + }`} + > + {editedBio?.length + ? editedBio?.length + : bio?.length + ? bio.length + : 0} + /2000 characters +

+ {bioError && ( +

{bioError}

+ )} +
- setSkillsCopy([...skills])} + +
+

20 + ? "text-red-500" + : "text-gray-500" + }`} + > + {`${updatedSkillsLength}/20 skills`} +

+ {skillsError && ( +

{skillsError}

+ )} +
- - setinterestsCopy([...interests]) - } + +
+

20 + ? "text-red-500" + : "text-gray-500" + }`} + > + {`${updatedInterestsLength}/20 skills`} +

+ {interestsError && ( +

{interestsError}

+ )} +
- +
diff --git a/src/components/Dashboard/profile/hooks/useUserInterests.ts b/src/components/Dashboard/profile/hooks/useUserInterests.ts new file mode 100644 index 0000000..86b415b --- /dev/null +++ b/src/components/Dashboard/profile/hooks/useUserInterests.ts @@ -0,0 +1,51 @@ +import { Tag, TagStatus } from "../types/profile-types.d" +import { useServerAction } from "@/src/hooks/useServerAction" +import { SearchTagsForSuggestionsAction } from "@/src/server-actions/Tag/Tag" +import { SetStateAction, useAtomValue, useSetAtom } from "jotai" +import { profileStore } from "@/src/store/profile/profileStore" + +type UseUserInterestsReturn = [ + interests: Tag[], // Current skills + setInterests: (value: SetStateAction) => void, // Interests setter + suggestions: Tag[], // Search suggestions + searchInterestsForUserInput: (name: string) => void, // Search function + searchInterestsLoading: boolean // Loading state +] + +const useUserInterests = (): UseUserInterestsReturn => { + const interests = useAtomValue(profileStore.interests) + const setInterests = useSetAtom(profileStore.interests) + + const [ + searchInterestsLoading, + searchedInterests, + searchInterestsError, + searchInterests + ] = useServerAction(SearchTagsForSuggestionsAction) + + const suggestions: Tag[] = searchedInterests?.data + ? searchedInterests.data.map((tag) => ({ + name: tag.name, + id: tag.id, + status: TagStatus[2] as const + })) + : [] + + const searchInterestsForUserInput = (name: string) => { + try { + searchInterests(name, "interest") + } catch (error) { + console.error(error) + } + } + + return [ + interests, + setInterests, + suggestions, + searchInterestsForUserInput, + searchInterestsLoading + ] +} + +export default useUserInterests diff --git a/src/components/Dashboard/profile/hooks/useUserSkills.ts b/src/components/Dashboard/profile/hooks/useUserSkills.ts new file mode 100644 index 0000000..eca61ed --- /dev/null +++ b/src/components/Dashboard/profile/hooks/useUserSkills.ts @@ -0,0 +1,47 @@ +import { Tag, TagStatus } from "../types/profile-types.d" +import { useServerAction } from "@/src/hooks/useServerAction" +import { SearchTagsForSuggestionsAction } from "@/src/server-actions/Tag/Tag" +import { SetStateAction, useAtomValue, useSetAtom } from "jotai" +import { profileStore } from "@/src/store/profile/profileStore" + +type UseUserSkillsReturn = [ + skills: Tag[], // Current skills + setSkills: (value: SetStateAction) => void, // Skills setter + suggestions: Tag[], // Search suggestions + searchSkillsForUserInput: (name: string) => void, // Search function + searchSkillsLoading: boolean // Loading state +] + +const useUserSkills = (): UseUserSkillsReturn => { + const skills = useAtomValue(profileStore.skills) + const setSkills = useSetAtom(profileStore.skills) + + const [searchSkillsLoading, searchedSkills, searchSkillsError, searchSkills] = + useServerAction(SearchTagsForSuggestionsAction) + + const suggestions: Tag[] = searchedSkills?.data + ? searchedSkills.data.map((tag) => ({ + name: tag.name, + id: tag.id, + status: TagStatus[2] as const + })) + : [] + + const searchSkillsForUserInput = (name: string) => { + try { + searchSkills(name, "skill") + } catch (error) { + console.error(error) + } + } + + return [ + skills, + setSkills, + suggestions, + searchSkillsForUserInput, + searchSkillsLoading + ] +} + +export default useUserSkills diff --git a/src/components/Dashboard/profile/profile-activities.tsx b/src/components/Dashboard/profile/profile-activities.tsx index f5279cd..088badc 100644 --- a/src/components/Dashboard/profile/profile-activities.tsx +++ b/src/components/Dashboard/profile/profile-activities.tsx @@ -1,18 +1,33 @@ -import { Activity } from "./types/profile-types" import { Card, CardTitle, CardDescription, CardContent, - CardHeader, + CardHeader } from "../../ui/card" import { StarIcon } from "lucide-react" +import { GetActivitiessForUserAction } from "@/src/server-actions/Activity/Activity" -type Props = { - activities: Activity[] +type ProfileActivitiesProps = { + userId: string } -const ProfileActivities: React.FC = (props) => { +const ProfileActivities: React.FC = async ({ + userId +}) => { + let activities + + try { + const res = await GetActivitiessForUserAction(userId) + if (res.success) { + activities = res.data + } else { + throw res.error + } + } catch (error) { + console.error(error) + } + return ( @@ -23,8 +38,8 @@ const ProfileActivities: React.FC = (props) => {
    - {props.activities.map((activity, i) => ( -
  • + {activities?.map((activity) => ( +
  • {activity.description}

    diff --git a/src/components/Dashboard/profile/profile-bio.tsx b/src/components/Dashboard/profile/profile-bio.tsx index 1bec7c0..aaa93bf 100644 --- a/src/components/Dashboard/profile/profile-bio.tsx +++ b/src/components/Dashboard/profile/profile-bio.tsx @@ -1,86 +1,143 @@ -'use client' +"use client" + import { Badge } from "../../ui/badge" import { Card, CardTitle, CardDescription, CardContent, - CardHeader, + CardHeader } from "../../ui/card" -import { Recommendation } from "./types/profile-types" +import { Recommendation, Tag, TagStatus } from "./types/profile-types.d" import EditProfileModal from "./edit-profile-modal" -import { useState } from "react" +import { useEffect, useState } from "react" +import { useServerAction } from "@/src/hooks/useServerAction" +import { GetUserBioForUserAction } from "@/src/server-actions/User/User" +import { GetTagsForUserAction } from "@/src/server-actions/Tag/Tag" +import { useAtomValue, useSetAtom } from "jotai" +import { userStore } from "@/src/store/user/userStore" +import { profileStore } from "@/src/store/profile/profileStore" +import Loader from "../../common/Loader/Loader" +import { LoaderSizes } from "../../common/Loader/loader-types.d" type Props = { - recommendations: Recommendation[] - skillTags: string[] - setSkillTags?: (tags: string[]) => void - interests: string[] - setInterests?: (tags: string[]) => void editable?: boolean } -const ProfileBio: React.FC = ({recommendations, skillTags, setSkillTags, interests, setInterests, editable=true}) => { - const [bio, setBio] = useState("hello world!") +const ProfileBio: React.FC = ({ editable = true }) => { + const [recommendations, setRecommendations] = useState([ + { + name: "Jane Doe", + text: "An exceptional developer with a keen eye for detail." + }, + { name: "John Smith", text: "Always delivers high-quality work on time." } + ]) + + const user = useAtomValue(userStore.Iam) + const setUserBio = useSetAtom(profileStore.bio) + const setUserSkills = useSetAtom(profileStore.skills) + const setUserInterests = useSetAtom(profileStore.interests) + const skills = useAtomValue(profileStore.skills) + const interests = useAtomValue(profileStore.interests) + const bio = useAtomValue(profileStore.bio) + + const [getBioLoading, bioData, getBioError, getBio] = useServerAction( + GetUserBioForUserAction + ) + const [getTagsLoading, tagsData, getTagsError, getTags] = + useServerAction(GetTagsForUserAction) + + useEffect(() => { + if (tagsData && tagsData.data) { + const skillTags = tagsData?.data + .filter((tag) => tag.type === "skill") + .map((tag) => ({ + id: tag.id, + name: tag.name, + status: TagStatus[1] as const + })) + const interestTags = tagsData?.data + .filter((tag) => tag.type === "interest") + .map((tag) => ({ + id: tag.id, + name: tag.name, + status: TagStatus[1] as const + })) + setUserInterests(interestTags) + setUserSkills(skillTags) + } + }, [tagsData]) + + useEffect(() => { + if (user) { + getBio(user?.external_auth_id) + getTags(user?.external_auth_id) + } + }, [user]) + + useEffect(() => { + setUserBio(bioData?.data as string) + }, [bioData]) return (
    Bio - { - editable && setSkillTags && setInterests && ( - - ) - } + {editable && }
    {bio}
    - -
    -
    -

    Skills

    -
    -
    - {skillTags.map((skill: string) => ( - - {skill} - - ))} -
    -
    -
    -
    -

    Interests

    -
    -
    - {interests.map((interest: string) => ( - - {interest} - - ))} -
    -
    -
    -

    Recommendations

    -
      - {recommendations.map((recommendation: Recommendation,i) => ( -
    • -

      "{recommendation.text}"

      -

      - - {recommendation.name} -

      -
    • - ))} -
    -
    + + {getTagsLoading || getBioLoading ? ( + + ) : ( + <> +
    +
    +

    Skills

    +
    +
    + {skills.map((skill: Tag) => ( + + {skill.name} + + ))} +
    +
    +
    +
    +

    interestTags

    +
    +
    + {interests.map((interest: Tag) => ( + + {interest.name} + + ))} +
    +
    +
    +

    Recommendations

    +
      + {recommendations.map((recommendation: Recommendation, i) => ( +
    • +

      "{recommendation.text}"

      +

      + - {recommendation.name} +

      +
    • + ))} +
    +
    + + )}
    ) diff --git a/src/components/Dashboard/profile/profile-rewards.tsx b/src/components/Dashboard/profile/profile-rewards.tsx index d8a8e16..f19a543 100644 --- a/src/components/Dashboard/profile/profile-rewards.tsx +++ b/src/components/Dashboard/profile/profile-rewards.tsx @@ -1,18 +1,31 @@ -import { Reward } from "./types/profile-types" import { Card, CardTitle, CardDescription, CardContent, - CardHeader, + CardHeader } from "../../ui/card" import { TrophyIcon } from "lucide-react" +import { GetRewardsForUserAction } from "@/src/server-actions/Reward/Reward" -type Props = { - rewards: Reward[] +type ProfileActivitiesProps = { + userId: string } -const ProfileRewards: React.FC = (props) => { +const ProfileRewards: React.FC = async ({ userId }) => { + let rewards + + try { + const res = await GetRewardsForUserAction(userId) + if (res.success) { + rewards = res.data + } else { + throw res.error + } + } catch (error) { + console.error(error) + } + return ( @@ -21,8 +34,8 @@ const ProfileRewards: React.FC = (props) => {
      - {props.rewards.map((reward: Reward,i) => ( -
    • + {rewards?.map((reward) => ( +
    • {reward.title}

      diff --git a/src/components/Dashboard/profile/types/profile-types.d.ts b/src/components/Dashboard/profile/types/profile-types.d.ts index 43f8870..1c1c06b 100644 --- a/src/components/Dashboard/profile/types/profile-types.d.ts +++ b/src/components/Dashboard/profile/types/profile-types.d.ts @@ -1,3 +1,5 @@ +import { InsertTag } from "@/src/db/schema" + export type Recommendation = { name: string text: string @@ -12,3 +14,24 @@ export type Activity = { date: string description: string } + +export type Tag = { + name: string + id?: number + status: TagStatus + deleted?: boolean +} + +export enum TagStatus { + 1 = "saved", + 2 = "selected", + 3 = "new" +} + +export type ProfileData = { + userId: string + bio: string + newTags: InsertTag[] + existingTags: InsertTag[] + deletedTagsIds: number[] +} diff --git a/src/components/TagsInput/TagsInput.tsx b/src/components/TagsInput/TagsInput.tsx new file mode 100644 index 0000000..2e33ee7 --- /dev/null +++ b/src/components/TagsInput/TagsInput.tsx @@ -0,0 +1,165 @@ +import { useState, useEffect, useRef } from "react" +import { X } from "lucide-react" +import { Tag, TagStatus } from "../dashboard/Profile/types/profile-types.d" + +type TagsInputProps = { + tags: Tag[] + updateTags: (tags: Tag[] | ((tags: Tag[]) => Tag[])) => void + suggestions: Tag[] + onChange: (tagName: string) => void + loadingSuggestions: boolean + autocomplete?: boolean +} + +const TagsInput: React.FC = ({ + tags, + updateTags, + suggestions, + loadingSuggestions, + onChange, + autocomplete = true +}) => { + const [showSuggestions, setShowSuggestions] = useState(false) + const timer = useRef() + + const tagInput = useRef(null) + + useEffect(() => { + return () => { + timer && clearTimeout(timer.current) + } + }, []) + + const handleInputChange = (e: React.ChangeEvent) => { + if (autocomplete) { + // Clear existing timer + timer && clearTimeout(timer.current) + // Set new timer for debouncing + if (e.target.value.length >= 2) { + timer.current = setTimeout(() => { + try { + setShowSuggestions(true) + onChange(e.target.value) + } catch (error) { + console.error("Error fetching suggestions:", error) + } + }, 800) + } else { + onChange(e.target.value) + } + } else { + setShowSuggestions(false) + } + } + + const handleNewTag = () => { + if ( + !tags.some( + (tag) => + tag?.name.toLowerCase() === + (tagInput.current as HTMLInputElement).value.toLowerCase() && + !tag.deleted + ) + ) { + updateTags((tags: Tag[]) => [ + ...tags, + { + name: + (tagInput.current as HTMLInputElement).value + .trim()[0] + .toUpperCase() + + (tagInput.current as HTMLInputElement).value + .substring(1) + .toLowerCase(), + status: TagStatus[3] + } + ]) + setShowSuggestions(false) + ;(tagInput.current as HTMLInputElement).value = "" + } + } + + const removeTag = (indexToRemove: number) => { + updateTags((tags) => + tags.with(indexToRemove, { ...tags[indexToRemove], deleted: true }) + ) + } + + const selectSuggestion = (suggestion: Tag) => { + if ( + !tags.some( + (tag) => + tag?.name.toLowerCase() === suggestion.name.toLowerCase() && + !tag.deleted + ) + ) { + updateTags((tags: Tag[]) => [...tags, suggestion]) + } + ;(tagInput.current as HTMLInputElement).value = "" + setShowSuggestions(false) + } + + return ( +
      +
      + {tags.map( + (tag, i) => + !tag.deleted && ( + + {tag?.name} + + + ) + )} + +
      + {showSuggestions && (tagInput.current as HTMLInputElement).value && ( +
      + {loadingSuggestions ? ( +
      Loading...
      + ) : suggestions.length === 0 ? ( +
      + +
      + ) : ( +
      + {suggestions.map((suggestion) => ( + + ))} +
      + )} +
      + )} +
      + ) +} + +export default TagsInput diff --git a/src/components/chips-input/chips-input.css b/src/components/chips-input/chips-input.css deleted file mode 100644 index e949e2c..0000000 --- a/src/components/chips-input/chips-input.css +++ /dev/null @@ -1,37 +0,0 @@ -.react-tagsinput { - background-color: transparent; - border: none; - height: fit-content; -} - -.react-tagsinput--focused { - border-color: none; -} - -.react-tagsinput-tag { - background-color: #262626; - border-radius: 2px; - border: none; - color: hsl(0, 0%, 98%); - display: inline-block; - font-family: sans-serif; - font-size: 13px; - font-weight: 400; - margin-bottom: 5px; - margin-right: 5px; - padding: 5px; -} - -.react-tagsinput-input { - background: transparent; - border: 0; - color: white; - font-family: sans-serif; - font-size: 13px; - font-weight: 400; - margin-bottom: 6px; - margin-top: 1px; - outline: none; - padding: 5px; - width: 80px; -} diff --git a/src/components/chips-input/index.tsx b/src/components/chips-input/index.tsx deleted file mode 100644 index 69303b7..0000000 --- a/src/components/chips-input/index.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import TagsInput from "react-tagsinput" -import "./chips-input.css" - -type ChipsInputProps = { - tags: string[] - updateTags: (tags: string[]) => void -} - -const ChipsInput: React.FC = (props) => { - return ( -
      - props.updateTags(tags)} - addOnPaste - inputProps={{ - className: "react-tagsinput-input", - placeholder: "" - }} - /> -
      - ) -} - -export default ChipsInput diff --git a/src/components/common/Loader/Loader.tsx b/src/components/common/Loader/Loader.tsx index c8d3e5c..3c58d5d 100644 --- a/src/components/common/Loader/Loader.tsx +++ b/src/components/common/Loader/Loader.tsx @@ -1,13 +1,28 @@ -import React from 'react' +import { LoaderSizes } from "./types/loader-types" -const Loader = () => { +type LoaderProps = { + size?: LoaderSizes +} + +const Loader: React.FC = ({ size = LoaderSizes.sm }) => { return ( - -
      - + {post.author.name[0]}
      @@ -53,21 +50,14 @@ const FilePost: React.FC = ({post, posts, setPosts}) => {
      - +
      {post.comments.map((comment: Comment) => ( ))}
      - +
      ) diff --git a/src/components/Dashboard/posts/post-image.tsx b/src/components/Dashboard/posts/post-image.tsx index 7103432..660af3c 100644 --- a/src/components/Dashboard/posts/post-image.tsx +++ b/src/components/Dashboard/posts/post-image.tsx @@ -1,10 +1,10 @@ -import { Post, Comment, PostFile, PostPoll } from "./types/posts-types" +import { Post, Comment, PostFile, PostPoll } from "./types/posts-types.d" import { Avatar, AvatarFallback, AvatarImage } from "@/src/components/ui/avatar" import { Card, CardContent, CardFooter, - CardHeader, + CardHeader } from "@/src/components/ui/card" import { Badge } from "@/src/components/ui/badge" import { Separator } from "@/src/components/ui/separator" diff --git a/src/components/Dashboard/posts/post-poll.tsx b/src/components/Dashboard/posts/post-poll.tsx index d095792..bf8b824 100644 --- a/src/components/Dashboard/posts/post-poll.tsx +++ b/src/components/Dashboard/posts/post-poll.tsx @@ -3,7 +3,7 @@ import { Card, CardContent, CardFooter, - CardHeader, + CardHeader } from "@/src/components/ui/card" import { Badge } from "@/src/components/ui/badge" import { Separator } from "@/src/components/ui/separator" @@ -13,7 +13,7 @@ import PostCommentForm from "./post-comment-form" import { RadioGroup } from "../../ui/radio-group" import { Label } from "../../ui/label" import { RadioGroupItem } from "../../ui/radio-group" -import { Comment, Post, PostFile, PostPoll } from "./types/posts-types" +import { Comment, Post, PostFile, PostPoll } from "./types/posts-types.d" type Props = { post: PostPoll diff --git a/src/components/Dashboard/posts/post-text.tsx b/src/components/Dashboard/posts/post-text.tsx index f511eda..494b7f5 100644 --- a/src/components/Dashboard/posts/post-text.tsx +++ b/src/components/Dashboard/posts/post-text.tsx @@ -1,10 +1,10 @@ -import { Post, Comment, PostFile, PostPoll } from "./types/posts-types" +import { Post, Comment, PostFile, PostPoll } from "./types/posts-types.d" import { Avatar, AvatarFallback, AvatarImage } from "@/src/components/ui/avatar" import { Card, CardContent, CardFooter, - CardHeader, + CardHeader } from "@/src/components/ui/card" import { Badge } from "@/src/components/ui/badge" import { Separator } from "@/src/components/ui/separator" diff --git a/src/components/Dashboard/profile/profile-bio.tsx b/src/components/Dashboard/profile/profile-bio.tsx index aaa93bf..d4d4e8e 100644 --- a/src/components/Dashboard/profile/profile-bio.tsx +++ b/src/components/Dashboard/profile/profile-bio.tsx @@ -18,7 +18,7 @@ import { useAtomValue, useSetAtom } from "jotai" import { userStore } from "@/src/store/user/userStore" import { profileStore } from "@/src/store/profile/profileStore" import Loader from "../../common/Loader/Loader" -import { LoaderSizes } from "../../common/Loader/loader-types.d" +import { LoaderSizes } from "../../common/Loader/types/loader-types.d" type Props = { editable?: boolean diff --git a/src/components/common/Loader/Loader.tsx b/src/components/common/Loader/Loader.tsx index 3c58d5d..976589f 100644 --- a/src/components/common/Loader/Loader.tsx +++ b/src/components/common/Loader/Loader.tsx @@ -1,4 +1,4 @@ -import { LoaderSizes } from "./types/loader-types" +import { LoaderSizes } from "./types/loader-types.d" type LoaderProps = { size?: LoaderSizes diff --git a/src/server-actions/User/User.ts b/src/server-actions/User/User.ts index 60c26a0..ef0fb34 100644 --- a/src/server-actions/User/User.ts +++ b/src/server-actions/User/User.ts @@ -4,7 +4,7 @@ import { GetUserBio, UpdateUserBio } from "@/src/db/data-access/user/query" import { CreateServerAction } from ".." import { AddTag } from "@/src/db/data-access/tag/query" import { AddUserTag, DeleteUserTags } from "@/src/db/data-access/tag/query" -import { ProfileData } from "@/src/components/dashboard/Profile/types/profile-types" +import { ProfileData } from "@/src/components/dashboard/Profile/types/profile-types.d" export const UpdateBioForUserAction = CreateServerAction( true, From 15836601e620838777f130d12707d59d7af918a1 Mon Sep 17 00:00:00 2001 From: Ammar Waheed Date: Sat, 4 Jan 2025 03:30:27 +0500 Subject: [PATCH 3/8] Iam update in userStore --- src/app/(dashboard)/profile/page.tsx | 16 ++++-- .../Dashboard/profile/profile-bio.tsx | 4 +- src/components/TagsInput/TagsInput.tsx | 2 +- src/server-actions/User/User.ts | 27 +++++----- src/services/auth/ClerkAuthListner.tsx | 52 +++++++++---------- src/store/profile/profileStore.ts | 2 +- 6 files changed, 56 insertions(+), 47 deletions(-) diff --git a/src/app/(dashboard)/profile/page.tsx b/src/app/(dashboard)/profile/page.tsx index 6fff4d4..6d798fc 100644 --- a/src/app/(dashboard)/profile/page.tsx +++ b/src/app/(dashboard)/profile/page.tsx @@ -1,12 +1,18 @@ -import ProfileScreen from '@/src/components/Dashboard/profile/ProfileScreen' -import React, { Suspense } from 'react' +import ProfileScreen from "@/src/components/Dashboard/profile/ProfileScreen" +import { Suspense } from "react" -const page = () => { +interface ProfilePageProps { + searchParams: { + tab?: string + } +} + +const ProfilePage: React.FC = ({ searchParams: { tab } }) => { return ( - + ) } -export default page \ No newline at end of file +export default ProfilePage diff --git a/src/components/Dashboard/profile/profile-bio.tsx b/src/components/Dashboard/profile/profile-bio.tsx index d4d4e8e..d0aaf59 100644 --- a/src/components/Dashboard/profile/profile-bio.tsx +++ b/src/components/Dashboard/profile/profile-bio.tsx @@ -44,7 +44,7 @@ const ProfileBio: React.FC = ({ editable = true }) => { const [getBioLoading, bioData, getBioError, getBio] = useServerAction( GetUserBioForUserAction ) - const [getTagsLoading, tagsData, getTagsError, getTags] = +const [getTagsLoading, tagsData, getTagsError, getTags] = useServerAction(GetTagsForUserAction) useEffect(() => { @@ -69,7 +69,7 @@ const ProfileBio: React.FC = ({ editable = true }) => { }, [tagsData]) useEffect(() => { - if (user) { + if (user) { getBio(user?.external_auth_id) getTags(user?.external_auth_id) } diff --git a/src/components/TagsInput/TagsInput.tsx b/src/components/TagsInput/TagsInput.tsx index 2e33ee7..8cad03d 100644 --- a/src/components/TagsInput/TagsInput.tsx +++ b/src/components/TagsInput/TagsInput.tsx @@ -1,6 +1,6 @@ import { useState, useEffect, useRef } from "react" import { X } from "lucide-react" -import { Tag, TagStatus } from "../dashboard/Profile/types/profile-types.d" +import { Tag, TagStatus } from "../Dashboard/profile/types/profile-types.d" type TagsInputProps = { tags: Tag[] diff --git a/src/server-actions/User/User.ts b/src/server-actions/User/User.ts index ef0fb34..a50b132 100644 --- a/src/server-actions/User/User.ts +++ b/src/server-actions/User/User.ts @@ -4,7 +4,7 @@ import { GetUserBio, UpdateUserBio } from "@/src/db/data-access/user/query" import { CreateServerAction } from ".." import { AddTag } from "@/src/db/data-access/tag/query" import { AddUserTag, DeleteUserTags } from "@/src/db/data-access/tag/query" -import { ProfileData } from "@/src/components/dashboard/Profile/types/profile-types.d" +import { ProfileData } from "@/src/components/Dashboard/profile/types/profile-types.d" export const UpdateBioForUserAction = CreateServerAction( true, @@ -47,18 +47,21 @@ export const SaveUserProfileAction = CreateServerAction( try { await UpdateUserBio(profileData.userId, profileData.bio) // add new tags - const insertedTags = await AddTag(profileData.newTags) - await AddUserTag( - insertedTags.map((tag) => { - return { user_id: profileData.userId, tag_id: tag.id } - }) - ) + if (profileData.newTags.length) { + const insertedTags = await AddTag(profileData.newTags) + await AddUserTag( + insertedTags.map((tag) => { + return { user_id: profileData.userId, tag_id: tag.id } + }) + ) + } // add existing tags - await AddUserTag( - profileData.existingTags.map((tag) => { - return { user_id: profileData.userId, tag_id: tag.id as number } - }) - ) + profileData.existingTags.length && + (await AddUserTag( + profileData.existingTags.map((tag) => { + return { user_id: profileData.userId, tag_id: tag.id as number } + }) + )) // delete tags await DeleteUserTags(profileData.userId, profileData.deletedTagsIds) return { diff --git a/src/services/auth/ClerkAuthListner.tsx b/src/services/auth/ClerkAuthListner.tsx index a1bff85..c0d8840 100644 --- a/src/services/auth/ClerkAuthListner.tsx +++ b/src/services/auth/ClerkAuthListner.tsx @@ -1,37 +1,37 @@ -'use client' -import React, { useEffect } from 'react'; -import { useSetAtom } from 'jotai'; -import { useAuth, useUser } from '@clerk/nextjs'; -import { SelectUser } from '@/src/db/schema'; -import { userStore } from '@/src/store/user/userStore'; -import { SelectUserByExternalId } from '@/src/db/data-access/user/query'; -import { UserResource } from '@clerk/types'; -import { AuthUserAction } from '@/src/server-actions/User/AuthUserAction'; +"use client" +import React, { useEffect } from "react" +import { useSetAtom } from "jotai" +import { useAuth, useUser } from "@clerk/nextjs" +import { SelectUser } from "@/src/db/schema" +import { userStore } from "@/src/store/user/userStore" +import { UserResource } from "@clerk/types" +import { AuthUserAction } from "@/src/server-actions/User/AuthUserAction" const ClerkAuthListener = () => { - const { isSignedIn , isLoaded } = useAuth(); - const { user } = useUser(); - const setUser = useSetAtom(userStore.AuthUser); + const { isSignedIn, isLoaded } = useAuth() + const { user } = useUser() + const setUser = useSetAtom(userStore.AuthUser) + const setIam = useSetAtom(userStore.Iam) - const handleSetUser = async (user: UserResource | null | undefined) => { - if (!user) return - const userRes = await AuthUserAction(); - if (!userRes) return - setUser(userRes); - }; + const handleSetUser = async (user: UserResource | null | undefined) => { + if (!user) return + const userRes: Omit | undefined = await AuthUserAction() + if (!userRes) return + setUser(userRes as SelectUser) + setIam(userRes as SelectUser) + } useEffect(() => { - if (!isLoaded) return; + if (!isLoaded) return if (isSignedIn && user) { handleSetUser(user) - } else { - setUser(null); + setUser(null) + setIam(null) } - }, [isSignedIn, user, setUser]); + }, [isSignedIn, user, setUser]) - return <>; + return <> +} -}; - -export default ClerkAuthListener; \ No newline at end of file +export default ClerkAuthListener diff --git a/src/store/profile/profileStore.ts b/src/store/profile/profileStore.ts index 2757c84..3696c6c 100644 --- a/src/store/profile/profileStore.ts +++ b/src/store/profile/profileStore.ts @@ -1,4 +1,4 @@ -import { Tag } from "@/src/components/dashboard/Profile/types/profile-types.d" +import { Tag } from "@/src/components/Dashboard/profile/types/profile-types.d" import { atom } from "jotai" const bio = atom("") From 982ae8724dfb8c88d0fa162af5623ad72cd57110 Mon Sep 17 00:00:00 2001 From: Ammar Waheed Date: Mon, 6 Jan 2025 02:01:09 +0500 Subject: [PATCH 4/8] server side rendering for recommendations --- .../Dashboard/profile/ProfileBioClient.tsx | 105 ++++++++++++ .../Dashboard/profile/ProfileScreen.tsx | 2 +- .../Dashboard/profile/edit-profile-modal.tsx | 58 ++++--- .../Dashboard/profile/profile-bio.tsx | 150 +++--------------- src/server-actions/User/User.ts | 2 +- 5 files changed, 163 insertions(+), 154 deletions(-) create mode 100644 src/components/Dashboard/profile/ProfileBioClient.tsx diff --git a/src/components/Dashboard/profile/ProfileBioClient.tsx b/src/components/Dashboard/profile/ProfileBioClient.tsx new file mode 100644 index 0000000..67620e1 --- /dev/null +++ b/src/components/Dashboard/profile/ProfileBioClient.tsx @@ -0,0 +1,105 @@ +import EditProfileModal from "./edit-profile-modal" +import { Badge } from "../../ui/badge" +import { useAtomValue, useSetAtom } from "jotai" +import { profileStore } from "@/src/store/profile/profileStore" +import { useServerAction } from "@/src/hooks/useServerAction" +import { GetBioForUserAction } from "@/src/server-actions/User/User" +import { GetTagsForUserAction } from "@/src/server-actions/Tag/Tag" +import { useEffect } from "react" +import { Tag, TagStatus } from "./types/profile-types" +import Loader from "../../common/Loader/Loader" +import { LoaderSizes } from "../../common/Loader/types/loader-types" + +type ProfileBioClientProps = { + editable?: boolean + userId: string +} + +const ProfileBioClient: React.FC = ({ + editable = true, + userId +}) => { + const setUserBio = useSetAtom(profileStore.bio) + const setUserSkills = useSetAtom(profileStore.skills) + const setUserInterests = useSetAtom(profileStore.interests) + const skills = useAtomValue(profileStore.skills) + const interests = useAtomValue(profileStore.interests) + const bio = useAtomValue(profileStore.bio) + + const [getBioLoading, bioData, getBioError, getBio] = + useServerAction(GetBioForUserAction) + const [getTagsLoading, tagsData, getTagsError, getTags] = + useServerAction(GetTagsForUserAction) + + useEffect(() => { + if (tagsData && tagsData.data) { + const skillTags = tagsData?.data + .filter((tag) => tag.type === "skill") + .map((tag) => ({ + id: tag.id, + name: tag.name, + status: TagStatus[1] as const + })) + const interestTags = tagsData?.data + .filter((tag) => tag.type === "interest") + .map((tag) => ({ + id: tag.id, + name: tag.name, + status: TagStatus[1] as const + })) + setUserInterests(interestTags) + setUserSkills(skillTags) + } + }, [tagsData]) + + useEffect(() => { + if (userId) { + getBio(userId) + getTags(userId) + } + }, [userId]) + + useEffect(() => { + setUserBio(bioData?.data as string) + }, [bioData]) + + return getTagsLoading || getBioLoading ? ( + + ) : ( + <> +
      +
      +

      Bio

      + {editable && } +
      +

      {bio}

      +
      +
      +
      +

      Skills

      +
      +
      + {skills.map((skill: Tag) => ( + + {skill.name} + + ))} +
      +
      +
      +
      +

      Interests

      +
      +
      + {interests.map((interest: Tag) => ( + + {interest.name} + + ))} +
      +
      + + ) +} + +export default ProfileBioClient diff --git a/src/components/Dashboard/profile/ProfileScreen.tsx b/src/components/Dashboard/profile/ProfileScreen.tsx index eb81fd2..c2cec9a 100644 --- a/src/components/Dashboard/profile/ProfileScreen.tsx +++ b/src/components/Dashboard/profile/ProfileScreen.tsx @@ -66,7 +66,7 @@ export default async function ProfileScreen({ tab }: ProfileScreenProps) { - + diff --git a/src/components/Dashboard/profile/edit-profile-modal.tsx b/src/components/Dashboard/profile/edit-profile-modal.tsx index fb6456e..8a66734 100644 --- a/src/components/Dashboard/profile/edit-profile-modal.tsx +++ b/src/components/Dashboard/profile/edit-profile-modal.tsx @@ -81,7 +81,6 @@ const EditProfileModal: React.FC = () => { editedBio && editedBio?.length > 2000 ? "Bio cannot exceed 2000 characters" : "" - const saveProfileChanges = async (e: React.FormEvent) => { e.preventDefault() try { @@ -98,52 +97,61 @@ const EditProfileModal: React.FC = () => { bio: editedBio ? editedBio : bio, newTags: [ ...skills - .filter((tag) => tag.status === TagStatus[3]) + .filter((tag) => tag.status === TagStatus[3] && !tag.deleted) .map((tag) => { return { name: tag.name, type: "skill" } }), ...interests - .filter((tag) => tag.status === TagStatus[3]) + .filter((tag) => tag.status === TagStatus[3] && !tag.deleted) .map((tag) => { return { name: tag.name, type: "interest" } }) ], existingTags: [ ...skills - .filter((tag) => tag.status === TagStatus[2]) + .filter((tag) => tag.status === TagStatus[2] && !tag.deleted) .map((tag) => { return { name: tag.name, id: tag.id, type: "skill" } }), ...interests - .filter((tag) => tag.status === TagStatus[2]) + .filter((tag) => tag.status === TagStatus[2] && !tag.deleted) .map((tag) => { return { name: tag.name, id: tag.id, type: "interest" } }) ], deletedTagsIds: [...deletedSkillsIds, ...deletedInterestsIds] } - await updateProfile(updatedProfileData) - // remove deleted skills - setSkills((skills: Tag[]) => - skills.filter( - (tag) => !deletedSkillsIds.includes(tag.id as number) && !tag.deleted + const res = await updateProfile(updatedProfileData) + if (res?.success) { + // remove deleted skills and update skills val in store + setSkills((skills: Tag[]) => + skills + .filter( + (tag) => + !deletedSkillsIds.includes(tag.id as number) && !tag.deleted + ) + .map((tag) => ({ ...tag, status: TagStatus[1] })) ) - ) - // remove deleted Interests - setInterests((interests: Tag[]) => - interests.filter( - (tag) => - !deletedInterestsIds.includes(tag.id as number) && !tag.deleted + // remove deleted Interests and update interests val in store + setInterests((interests: Tag[]) => + interests + .filter( + (tag) => + !deletedInterestsIds.includes(tag.id as number) && !tag.deleted + ) + .map((tag) => ({ ...tag, status: TagStatus[1] })) ) - ) - editedBio && setBio(editedBio) - setIsOpen(false) - setEditedBio("") - toast({ - title: "Profile updated", - description: "Your changes have been saved successfully.", - duration: 3000 - }) + editedBio && setBio(editedBio) + setIsOpen(false) + setEditedBio("") + toast({ + title: "Profile updated", + description: "Your changes have been saved successfully.", + duration: 3000 + }) + } else { + throw res?.error + } } catch (error) { toast({ variant: "destructive", diff --git a/src/components/Dashboard/profile/profile-bio.tsx b/src/components/Dashboard/profile/profile-bio.tsx index d0aaf59..cb8cf29 100644 --- a/src/components/Dashboard/profile/profile-bio.tsx +++ b/src/components/Dashboard/profile/profile-bio.tsx @@ -1,30 +1,12 @@ -"use client" +import { Card, CardContent } from "../../ui/card" +import ProfileBioClient from "./ProfileBioClient" +import { Recommendation } from "./types/profile-types.d" -import { Badge } from "../../ui/badge" -import { - Card, - CardTitle, - CardDescription, - CardContent, - CardHeader -} from "../../ui/card" -import { Recommendation, Tag, TagStatus } from "./types/profile-types.d" -import EditProfileModal from "./edit-profile-modal" -import { useEffect, useState } from "react" -import { useServerAction } from "@/src/hooks/useServerAction" -import { GetUserBioForUserAction } from "@/src/server-actions/User/User" -import { GetTagsForUserAction } from "@/src/server-actions/Tag/Tag" -import { useAtomValue, useSetAtom } from "jotai" -import { userStore } from "@/src/store/user/userStore" -import { profileStore } from "@/src/store/profile/profileStore" -import Loader from "../../common/Loader/Loader" -import { LoaderSizes } from "../../common/Loader/types/loader-types.d" - -type Props = { - editable?: boolean +type ProfileBioProps = { + userId: string } -const ProfileBio: React.FC = ({ editable = true }) => { +const ProfileBio: React.FC = ({ userId }) => { const [recommendations, setRecommendations] = useState([ { name: "Jane Doe", @@ -33,111 +15,25 @@ const ProfileBio: React.FC = ({ editable = true }) => { { name: "John Smith", text: "Always delivers high-quality work on time." } ]) - const user = useAtomValue(userStore.Iam) - const setUserBio = useSetAtom(profileStore.bio) - const setUserSkills = useSetAtom(profileStore.skills) - const setUserInterests = useSetAtom(profileStore.interests) - const skills = useAtomValue(profileStore.skills) - const interests = useAtomValue(profileStore.interests) - const bio = useAtomValue(profileStore.bio) - - const [getBioLoading, bioData, getBioError, getBio] = useServerAction( - GetUserBioForUserAction - ) -const [getTagsLoading, tagsData, getTagsError, getTags] = - useServerAction(GetTagsForUserAction) - - useEffect(() => { - if (tagsData && tagsData.data) { - const skillTags = tagsData?.data - .filter((tag) => tag.type === "skill") - .map((tag) => ({ - id: tag.id, - name: tag.name, - status: TagStatus[1] as const - })) - const interestTags = tagsData?.data - .filter((tag) => tag.type === "interest") - .map((tag) => ({ - id: tag.id, - name: tag.name, - status: TagStatus[1] as const - })) - setUserInterests(interestTags) - setUserSkills(skillTags) - } - }, [tagsData]) - - useEffect(() => { - if (user) { - getBio(user?.external_auth_id) - getTags(user?.external_auth_id) - } - }, [user]) - - useEffect(() => { - setUserBio(bioData?.data as string) - }, [bioData]) - return ( - -
      - Bio - {editable && } -
      - {bio} -
      - - {getTagsLoading || getBioLoading ? ( - - ) : ( - <> -
      -
      -

      Skills

      -
      -
      - {skills.map((skill: Tag) => ( - - {skill.name} - - ))} -
      -
      -
      -
      -

      interestTags

      -
      -
      - {interests.map((interest: Tag) => ( - - {interest.name} - - ))} -
      -
      -
      -

      Recommendations

      -
        - {recommendations.map((recommendation: Recommendation, i) => ( -
      • -

        "{recommendation.text}"

        -

        - - {recommendation.name} -

        -
      • - ))} -
      -
      - - )} + + <> + +
      +

      Recommendations

      +
        + {recommendations.map((recommendation: Recommendation, i) => ( +
      • +

        "{recommendation.text}"

        +

        + - {recommendation.name} +

        +
      • + ))} +
      +
      +
      ) diff --git a/src/server-actions/User/User.ts b/src/server-actions/User/User.ts index a50b132..c4394fc 100644 --- a/src/server-actions/User/User.ts +++ b/src/server-actions/User/User.ts @@ -23,7 +23,7 @@ export const UpdateBioForUserAction = CreateServerAction( } ) -export const GetUserBioForUserAction = CreateServerAction( +export const GetBioForUserAction = CreateServerAction( true, async (userId: string) => { try { From 3aa8e00ed32bc44c7732fd8cff71777a2f0ab030 Mon Sep 17 00:00:00 2001 From: Ammar Waheed Date: Mon, 6 Jan 2025 15:06:05 +0500 Subject: [PATCH 5/8] recommendations table --- .../Dashboard/profile/ProfileBioClient.tsx | 42 +- .../Dashboard/profile/ProfileScreen.tsx | 8 +- .../Dashboard/profile/profile-bio.tsx | 23 +- src/db/data-access/recommendation/query.ts | 11 + src/db/data-access/reward/query.ts | 2 +- src/db/data-access/user/query.ts | 19 +- src/db/migrations/0016_slow_morlocks.sql | 99 +++ src/db/migrations/meta/0016_snapshot.json | 748 ++++++++++++++++++ src/db/migrations/meta/_journal.json | 7 + src/db/schema.ts | 11 + .../Recommendations/Recommendations.ts | 26 + src/server-actions/Reward/Reward.ts | 4 +- 12 files changed, 965 insertions(+), 35 deletions(-) create mode 100644 src/db/migrations/0016_slow_morlocks.sql create mode 100644 src/db/migrations/meta/0016_snapshot.json create mode 100644 src/server-actions/Recommendations/Recommendations.ts diff --git a/src/components/Dashboard/profile/ProfileBioClient.tsx b/src/components/Dashboard/profile/ProfileBioClient.tsx index 67620e1..a9fa7bc 100644 --- a/src/components/Dashboard/profile/ProfileBioClient.tsx +++ b/src/components/Dashboard/profile/ProfileBioClient.tsx @@ -1,3 +1,5 @@ +"use client" + import EditProfileModal from "./edit-profile-modal" import { Badge } from "../../ui/badge" import { useAtomValue, useSetAtom } from "jotai" @@ -6,9 +8,9 @@ import { useServerAction } from "@/src/hooks/useServerAction" import { GetBioForUserAction } from "@/src/server-actions/User/User" import { GetTagsForUserAction } from "@/src/server-actions/Tag/Tag" import { useEffect } from "react" -import { Tag, TagStatus } from "./types/profile-types" +import { Tag, TagStatus } from "./types/profile-types.d" import Loader from "../../common/Loader/Loader" -import { LoaderSizes } from "../../common/Loader/types/loader-types" +import { LoaderSizes } from "../../common/Loader/types/loader-types.d" type ProfileBioClientProps = { editable?: boolean @@ -64,7 +66,13 @@ const ProfileBioClient: React.FC = ({ }, [bioData]) return getTagsLoading || getBioLoading ? ( - +
      + +
      ) : ( <>
      @@ -72,18 +80,22 @@ const ProfileBioClient: React.FC = ({

      Bio

      {editable && } -

      {bio}

      +

      + {bio ?? "Time to shine ✨ Tell the world about yourself"} +

      Skills

      - {skills.map((skill: Tag) => ( - - {skill.name} - - ))} + {skills.length + ? skills.map((skill: Tag) => ( + + {skill.name} + + )) + : "What are you great at? Don't be shy!"}
      @@ -91,11 +103,13 @@ const ProfileBioClient: React.FC = ({

      Interests

      - {interests.map((interest: Tag) => ( - - {interest.name} - - ))} + {interests.length + ? interests.map((interest: Tag) => ( + + {interest.name} + + )) + : "Share your passions, hobbies, and guilty coding pleasures"}
      diff --git a/src/components/Dashboard/profile/ProfileScreen.tsx b/src/components/Dashboard/profile/ProfileScreen.tsx index c2cec9a..d1cece7 100644 --- a/src/components/Dashboard/profile/ProfileScreen.tsx +++ b/src/components/Dashboard/profile/ProfileScreen.tsx @@ -58,12 +58,12 @@ export default async function ProfileScreen({ tab }: ProfileScreenProps) { Activity - + {/* Calendar - + */} @@ -74,9 +74,9 @@ export default async function ProfileScreen({ tab }: ProfileScreenProps) { - + {/* - + */}
      ) diff --git a/src/components/Dashboard/profile/profile-bio.tsx b/src/components/Dashboard/profile/profile-bio.tsx index cb8cf29..b578baa 100644 --- a/src/components/Dashboard/profile/profile-bio.tsx +++ b/src/components/Dashboard/profile/profile-bio.tsx @@ -1,33 +1,30 @@ +import { FetchUserRecommendationsAction } from "@/src/server-actions/Recommendations/Recommendations" import { Card, CardContent } from "../../ui/card" import ProfileBioClient from "./ProfileBioClient" -import { Recommendation } from "./types/profile-types.d" type ProfileBioProps = { userId: string } -const ProfileBio: React.FC = ({ userId }) => { - const [recommendations, setRecommendations] = useState([ - { - name: "Jane Doe", - text: "An exceptional developer with a keen eye for detail." - }, - { name: "John Smith", text: "Always delivers high-quality work on time." } - ]) +const ProfileBio: React.FC = async ({ userId }) => { + const recommendations = await FetchUserRecommendationsAction(userId) + console.log(recommendations); return ( - + <>

      Recommendations

        - {recommendations.map((recommendation: Recommendation, i) => ( + {recommendations.map((recommendation, i) => (
      • -

        "{recommendation.text}"

        +

        + "{recommendation.content}" +

        - - {recommendation.name} + - {recommendation.recommender}

      • ))} diff --git a/src/db/data-access/recommendation/query.ts b/src/db/data-access/recommendation/query.ts index e69de29..5f3589b 100644 --- a/src/db/data-access/recommendation/query.ts +++ b/src/db/data-access/recommendation/query.ts @@ -0,0 +1,11 @@ +import { recommendationsTable } from "./../../schema" +import { db } from "../.." +import { eq } from "drizzle-orm" + +export const GetRecommendations = async (id: string) => { + const results = await db + .select() + .from(recommendationsTable) + .where(eq(recommendationsTable.receiver_id, id)) + return results ?? [] +} diff --git a/src/db/data-access/reward/query.ts b/src/db/data-access/reward/query.ts index c2d54bd..0dcf80d 100644 --- a/src/db/data-access/reward/query.ts +++ b/src/db/data-access/reward/query.ts @@ -11,7 +11,7 @@ export const AddReward = async (data: InsertReward[]) => { return await db.insert(rewardsTable).values(data).returning() } -export const getRewardsById = async (ids: number[]) => { +export const GetRewardsById = async (ids: number[]) => { const results = await db .select() .from(rewardsTable) diff --git a/src/db/data-access/user/query.ts b/src/db/data-access/user/query.ts index 653b2dc..ad9a4e5 100644 --- a/src/db/data-access/user/query.ts +++ b/src/db/data-access/user/query.ts @@ -1,4 +1,4 @@ -import { eq, like } from "drizzle-orm" +import { eq, inArray, like } from "drizzle-orm" import { db } from "../.." import { InsertUser, usersTable } from "../../schema" @@ -31,6 +31,23 @@ export async function SelectUserByExternalId(id: string) { }) } +export async function GetUsersFullName(ids: string[]) { + const uniqueIds = [...new Set(ids)] // Get unique IDs for the query + const users = await db.query.usersTable.findMany({ + columns: { + first_name: true, + last_name: true, + external_auth_id: true // Need this to match with input ids + }, + where: (usersTable) => inArray(usersTable.external_auth_id, uniqueIds) + }) + // Map over original ids array to maintain order and duplicates + return ids.map((id) => { + const user = users.find((u) => u.external_auth_id === id) + return user ? `${user.first_name} ${user.last_name}` : "" + }) +} + export async function SelectUserByEmail(email: string) { return await db.query.usersTable.findFirst({ where: eq(usersTable.email, email) diff --git a/src/db/migrations/0016_slow_morlocks.sql b/src/db/migrations/0016_slow_morlocks.sql new file mode 100644 index 0000000..a9d0e2f --- /dev/null +++ b/src/db/migrations/0016_slow_morlocks.sql @@ -0,0 +1,99 @@ +CREATE TABLE `activities` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `title` text NOT NULL, + `date` text NOT NULL, + `description` text NOT NULL, + `type` text NOT NULL, + `updated_at` text, + `created_at` text DEFAULT CURRENT_TIMESTAMP, + `deleted_at` text +); +--> statement-breakpoint +CREATE TABLE `chat` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `channel_id` text NOT NULL, + `name` text, + `type` text, + `avatar` text, + `last_message` text, + `unread_count` integer DEFAULT 0 NOT NULL, + `is_group` integer DEFAULT 0 NOT NULL, + `updated_at` text, + `created_at` text DEFAULT CURRENT_TIMESTAMP, + `deleted_at` text +); +--> statement-breakpoint +CREATE TABLE `recommendations` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `content` text NOT NULL, + `recommender_id` text NOT NULL, + `receiver_id` text NOT NULL, + `updated_at` text, + `created_at` text DEFAULT CURRENT_TIMESTAMP, + `deleted_at` text +); +--> statement-breakpoint +CREATE TABLE `rewards` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `title` text NOT NULL, + `description` text NOT NULL, + `badge_type` text NOT NULL, + `updated_at` text, + `created_at` text DEFAULT CURRENT_TIMESTAMP, + `deleted_at` text +); +--> statement-breakpoint +CREATE TABLE `tags` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `name` text NOT NULL, + `type` text NOT NULL, + `updated_at` text, + `created_at` text DEFAULT CURRENT_TIMESTAMP, + `deleted_at` text +); +--> statement-breakpoint +CREATE TABLE `user_activities` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `user_id` text NOT NULL, + `activity_id` integer NOT NULL +); +--> statement-breakpoint +CREATE TABLE `user_rewards` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `user_id` text NOT NULL, + `reward_id` integer NOT NULL +); +--> statement-breakpoint +CREATE TABLE `user_tags` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `user_id` text NOT NULL, + `tag_id` integer NOT NULL +); +--> statement-breakpoint +DROP TABLE `chats`;--> statement-breakpoint +DROP TABLE `user_messages`;--> statement-breakpoint +DROP INDEX IF EXISTS "users_email_unique";--> statement-breakpoint +DROP INDEX IF EXISTS "users_external_auth_id_unique";--> statement-breakpoint +ALTER TABLE `messages` ALTER COLUMN "sender_id" TO "sender_id" integer NOT NULL;--> statement-breakpoint +CREATE UNIQUE INDEX `users_email_unique` ON `users` (`email`);--> statement-breakpoint +CREATE UNIQUE INDEX `users_external_auth_id_unique` ON `users` (`external_auth_id`);--> statement-breakpoint +ALTER TABLE `messages` ADD `timestamp` integer NOT NULL;--> statement-breakpoint +PRAGMA foreign_keys=OFF;--> statement-breakpoint +CREATE TABLE `__new_users` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `first_name` text NOT NULL, + `last_name` text NOT NULL, + `email` text NOT NULL, + `external_auth_id` text NOT NULL, + `profile_url` text, + `unique_id` text(36), + `bio` text, + `meta` text +); +--> statement-breakpoint +INSERT INTO `__new_users`("id", "first_name", "last_name", "email", "external_auth_id", "profile_url", "unique_id", "bio", "meta") SELECT "id", "first_name", "last_name", "email", "external_auth_id", "profile_url", "unique_id", "bio", "meta" FROM `users`;--> statement-breakpoint +DROP TABLE `users`;--> statement-breakpoint +ALTER TABLE `__new_users` RENAME TO `users`;--> statement-breakpoint +PRAGMA foreign_keys=ON;--> statement-breakpoint +ALTER TABLE `user_chats` ALTER COLUMN "user_id" TO "user_id" text NOT NULL REFERENCES users(unique_id) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `user_chats` ALTER COLUMN "chat_id" TO "chat_id" integer NOT NULL REFERENCES chat(id) ON DELETE no action ON UPDATE no action; \ No newline at end of file diff --git a/src/db/migrations/meta/0016_snapshot.json b/src/db/migrations/meta/0016_snapshot.json new file mode 100644 index 0000000..15ac720 --- /dev/null +++ b/src/db/migrations/meta/0016_snapshot.json @@ -0,0 +1,748 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "73d1c429-570d-419b-92f2-f576a2a3cc88", + "prevId": "7b8ae6d9-e108-43af-8e92-8576a9e73faa", + "tables": { + "activities": { + "name": "activities", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "date": { + "name": "date", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "chat": { + "name": "chat", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "avatar": { + "name": "avatar", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_message": { + "name": "last_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "unread_count": { + "name": "unread_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "is_group": { + "name": "is_group", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "messages": { + "name": "messages", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "chat_id": { + "name": "chat_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sender_id": { + "name": "sender_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "timestamp": { + "name": "timestamp", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "recommendations": { + "name": "recommendations", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "recommender_id": { + "name": "recommender_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "receiver_id": { + "name": "receiver_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "rewards": { + "name": "rewards", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "badge_type": { + "name": "badge_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "tags": { + "name": "tags", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_activities": { + "name": "user_activities", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "activity_id": { + "name": "activity_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_chats": { + "name": "user_chats", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "chat_id": { + "name": "chat_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_chats_user_id_users_unique_id_fk": { + "name": "user_chats_user_id_users_unique_id_fk", + "tableFrom": "user_chats", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "unique_id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "user_chats_chat_id_chat_id_fk": { + "name": "user_chats_chat_id_chat_id_fk", + "tableFrom": "user_chats", + "tableTo": "chat", + "columnsFrom": [ + "chat_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_chats_user_id_chat_id_pk": { + "columns": [ + "user_id", + "chat_id" + ], + "name": "user_chats_user_id_chat_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_contacts": { + "name": "user_contacts", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "contact_id": { + "name": "contact_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_requested": { + "name": "is_requested", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "is_accepted": { + "name": "is_accepted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "is_blocked": { + "name": "is_blocked", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "is_following": { + "name": "is_following", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "user_contacts_user_id_contact_id_pk": { + "columns": [ + "user_id", + "contact_id" + ], + "name": "user_contacts_user_id_contact_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_rewards": { + "name": "user_rewards", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reward_id": { + "name": "reward_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_tags": { + "name": "user_tags", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "tag_id": { + "name": "tag_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "external_auth_id": { + "name": "external_auth_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "profile_url": { + "name": "profile_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "unique_id": { + "name": "unique_id", + "type": "text(36)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "bio": { + "name": "bio", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta": { + "name": "meta", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "users_email_unique": { + "name": "users_email_unique", + "columns": [ + "email" + ], + "isUnique": true + }, + "users_external_auth_id_unique": { + "name": "users_external_auth_id_unique", + "columns": [ + "external_auth_id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/src/db/migrations/meta/_journal.json b/src/db/migrations/meta/_journal.json index f40a2a4..60ef856 100644 --- a/src/db/migrations/meta/_journal.json +++ b/src/db/migrations/meta/_journal.json @@ -113,6 +113,13 @@ "when": 1735564128127, "tag": "0015_lame_quasar", "breakpoints": true + }, + { + "idx": 16, + "version": "6", + "when": 1736149590544, + "tag": "0016_slow_morlocks", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/db/schema.ts b/src/db/schema.ts index c6a1da6..6f88471 100644 --- a/src/db/schema.ts +++ b/src/db/schema.ts @@ -189,3 +189,14 @@ export const userActivitiesTable = sqliteTable("user_activities", { export type InsertUserActivity = typeof userActivitiesTable.$inferInsert export type SelectUserActivity = typeof userActivitiesTable.$inferSelect + +export const recommendationsTable = sqliteTable("recommendations", { + id: int().primaryKey({ autoIncrement: true }), + content: text().notNull(), + recommender_id: text().notNull(), + receiver_id: text().notNull(), + ...timestamps +}) + +export type InsertRecommendation = typeof recommendationsTable.$inferInsert +export type SelectRecommendation = typeof recommendationsTable.$inferSelect diff --git a/src/server-actions/Recommendations/Recommendations.ts b/src/server-actions/Recommendations/Recommendations.ts new file mode 100644 index 0000000..bfc4805 --- /dev/null +++ b/src/server-actions/Recommendations/Recommendations.ts @@ -0,0 +1,26 @@ +"use server" + +import { + GetUsersFullName +} from "../../db/data-access/user/query" +import { GetRecommendations } from "../../db/data-access/recommendation/query" +import { CreateServerAction } from ".." + +export const FetchUserRecommendationsAction = CreateServerAction( + true, + async (externalAuthId: string) => { + try { + const recommendations = await GetRecommendations(externalAuthId) + const RecommenderNames = await GetUsersFullName( + recommendations.map((recommendation) => recommendation.recommender_id) + ) + return recommendations.map((recommendation, i) => ({ + ...recommendation, + recommender: RecommenderNames[i] + })) + } catch (error) { + console.error("Error fetching recommendations:", error) + throw error + } + } +) diff --git a/src/server-actions/Reward/Reward.ts b/src/server-actions/Reward/Reward.ts index fef6cf9..51edb67 100644 --- a/src/server-actions/Reward/Reward.ts +++ b/src/server-actions/Reward/Reward.ts @@ -2,7 +2,7 @@ import { InsertReward, InsertUserReward } from "@/src/db/schema" import { CreateServerAction } from ".." -import { AddReward, getRewardsById } from "@/src/db/data-access/reward/query" +import { AddReward, GetRewardsById } from "@/src/db/data-access/reward/query" import { AddRewardForUser, GetRewardIdsForUser @@ -37,7 +37,7 @@ export const GetRewardsForUserAction = CreateServerAction( async (userId: string) => { try { const rewardIds = await GetRewardIdsForUser(userId) - const rewards = await getRewardsById(rewardIds) + const rewards = await GetRewardsById(rewardIds) return { success: true, data: rewards } } catch (error) { return { success: false, error: error } From 5663c8d1f9aa35b5ca33951065a8df78740bbd5f Mon Sep 17 00:00:00 2001 From: Ammar Waheed Date: Wed, 8 Jan 2025 10:14:45 +0500 Subject: [PATCH 6/8] updated schema --- .../Dashboard/profile/ProfileBioClient.tsx | 46 +- .../Dashboard/profile/edit-profile-modal.tsx | 16 +- .../profile/hooks/useUserInterests.ts | 2 +- .../Dashboard/profile/hooks/useUserSkills.ts | 2 +- .../Dashboard/profile/profile-bio.tsx | 1 - .../profile/types/profile-types.d.ts | 6 +- src/components/TagsInput/TagsInput.tsx | 2 +- src/db/data-access/user/query.ts | 4 +- src/db/migrations/0017_thin_titania.sql | 51 ++ src/db/migrations/0018_calm_magus.sql | 1 + src/db/migrations/meta/0017_snapshot.json | 731 +++++++++++++++++ src/db/migrations/meta/0018_snapshot.json | 738 ++++++++++++++++++ src/db/migrations/meta/_journal.json | 14 + src/db/schema.ts | 172 ++-- src/server-actions/User/User.ts | 3 +- 15 files changed, 1689 insertions(+), 100 deletions(-) create mode 100644 src/db/migrations/0017_thin_titania.sql create mode 100644 src/db/migrations/0018_calm_magus.sql create mode 100644 src/db/migrations/meta/0017_snapshot.json create mode 100644 src/db/migrations/meta/0018_snapshot.json diff --git a/src/components/Dashboard/profile/ProfileBioClient.tsx b/src/components/Dashboard/profile/ProfileBioClient.tsx index a9fa7bc..a2a253c 100644 --- a/src/components/Dashboard/profile/ProfileBioClient.tsx +++ b/src/components/Dashboard/profile/ProfileBioClient.tsx @@ -40,14 +40,14 @@ const ProfileBioClient: React.FC = ({ .map((tag) => ({ id: tag.id, name: tag.name, - status: TagStatus[1] as const + status: TagStatus.saved as const })) const interestTags = tagsData?.data .filter((tag) => tag.type === "interest") .map((tag) => ({ id: tag.id, name: tag.name, - status: TagStatus[1] as const + status: TagStatus.saved as const })) setUserInterests(interestTags) setUserSkills(skillTags) @@ -81,7 +81,11 @@ const ProfileBioClient: React.FC = ({ {editable && }

        - {bio ?? "Time to shine ✨ Tell the world about yourself"} + {bio ?? ( + + Time to shine ✨ Tell the world about yourself + + )}

      @@ -89,13 +93,17 @@ const ProfileBioClient: React.FC = ({

      Skills

      - {skills.length - ? skills.map((skill: Tag) => ( - - {skill.name} - - )) - : "What are you great at? Don't be shy!"} + {skills.length ? ( + skills.map((skill: Tag) => ( + + {skill.name} + + )) + ) : ( + + HTML ninja? 🥷 Python wizard? 🪄 Show off your superpowers! + + )}
      @@ -103,13 +111,17 @@ const ProfileBioClient: React.FC = ({

      Interests

      - {interests.length - ? interests.map((interest: Tag) => ( - - {interest.name} - - )) - : "Share your passions, hobbies, and guilty coding pleasures"} + {interests.length ? ( + interests.map((interest: Tag) => ( + + {interest.name} + + )) + ) : ( + + 💿 Share your passions, hobbies, and guilty coding pleasures 💾 + + )}
    diff --git a/src/components/Dashboard/profile/edit-profile-modal.tsx b/src/components/Dashboard/profile/edit-profile-modal.tsx index 8a66734..7dafe82 100644 --- a/src/components/Dashboard/profile/edit-profile-modal.tsx +++ b/src/components/Dashboard/profile/edit-profile-modal.tsx @@ -85,11 +85,11 @@ const EditProfileModal: React.FC = () => { e.preventDefault() try { const deletedSkillsIds: number[] = skills - .filter((skill) => skill.deleted && skill.status === TagStatus[1]) + .filter((skill) => skill.deleted && skill.status === TagStatus.saved) .map((skill) => skill.id as number) const deletedInterestsIds: number[] = interests .filter( - (interest) => interest.deleted && interest.status === TagStatus[1] + (interest) => interest.deleted && interest.status === TagStatus.saved ) .map((interest) => interest.id as number) const updatedProfileData: ProfileData = { @@ -97,24 +97,24 @@ const EditProfileModal: React.FC = () => { bio: editedBio ? editedBio : bio, newTags: [ ...skills - .filter((tag) => tag.status === TagStatus[3] && !tag.deleted) + .filter((tag) => tag.status === TagStatus.new && !tag.deleted) .map((tag) => { return { name: tag.name, type: "skill" } }), ...interests - .filter((tag) => tag.status === TagStatus[3] && !tag.deleted) + .filter((tag) => tag.status === TagStatus.new && !tag.deleted) .map((tag) => { return { name: tag.name, type: "interest" } }) ], existingTags: [ ...skills - .filter((tag) => tag.status === TagStatus[2] && !tag.deleted) + .filter((tag) => tag.status === TagStatus.selected && !tag.deleted) .map((tag) => { return { name: tag.name, id: tag.id, type: "skill" } }), ...interests - .filter((tag) => tag.status === TagStatus[2] && !tag.deleted) + .filter((tag) => tag.status === TagStatus.selected && !tag.deleted) .map((tag) => { return { name: tag.name, id: tag.id, type: "interest" } }) @@ -130,7 +130,7 @@ const EditProfileModal: React.FC = () => { (tag) => !deletedSkillsIds.includes(tag.id as number) && !tag.deleted ) - .map((tag) => ({ ...tag, status: TagStatus[1] })) + .map((tag) => ({ ...tag, status: TagStatus.saved })) ) // remove deleted Interests and update interests val in store setInterests((interests: Tag[]) => @@ -139,7 +139,7 @@ const EditProfileModal: React.FC = () => { (tag) => !deletedInterestsIds.includes(tag.id as number) && !tag.deleted ) - .map((tag) => ({ ...tag, status: TagStatus[1] })) + .map((tag) => ({ ...tag, status: TagStatus.saved })) ) editedBio && setBio(editedBio) setIsOpen(false) diff --git a/src/components/Dashboard/profile/hooks/useUserInterests.ts b/src/components/Dashboard/profile/hooks/useUserInterests.ts index 86b415b..8a6e245 100644 --- a/src/components/Dashboard/profile/hooks/useUserInterests.ts +++ b/src/components/Dashboard/profile/hooks/useUserInterests.ts @@ -27,7 +27,7 @@ const useUserInterests = (): UseUserInterestsReturn => { ? searchedInterests.data.map((tag) => ({ name: tag.name, id: tag.id, - status: TagStatus[2] as const + status: TagStatus.selected as const })) : [] diff --git a/src/components/Dashboard/profile/hooks/useUserSkills.ts b/src/components/Dashboard/profile/hooks/useUserSkills.ts index eca61ed..ab3581b 100644 --- a/src/components/Dashboard/profile/hooks/useUserSkills.ts +++ b/src/components/Dashboard/profile/hooks/useUserSkills.ts @@ -23,7 +23,7 @@ const useUserSkills = (): UseUserSkillsReturn => { ? searchedSkills.data.map((tag) => ({ name: tag.name, id: tag.id, - status: TagStatus[2] as const + status: TagStatus.selected as const })) : [] diff --git a/src/components/Dashboard/profile/profile-bio.tsx b/src/components/Dashboard/profile/profile-bio.tsx index b578baa..a8e2e58 100644 --- a/src/components/Dashboard/profile/profile-bio.tsx +++ b/src/components/Dashboard/profile/profile-bio.tsx @@ -8,7 +8,6 @@ type ProfileBioProps = { const ProfileBio: React.FC = async ({ userId }) => { const recommendations = await FetchUserRecommendationsAction(userId) - console.log(recommendations); return ( diff --git a/src/components/Dashboard/profile/types/profile-types.d.ts b/src/components/Dashboard/profile/types/profile-types.d.ts index 1c1c06b..cd0cba8 100644 --- a/src/components/Dashboard/profile/types/profile-types.d.ts +++ b/src/components/Dashboard/profile/types/profile-types.d.ts @@ -23,9 +23,9 @@ export type Tag = { } export enum TagStatus { - 1 = "saved", - 2 = "selected", - 3 = "new" + saved = "saved", + selected = "selected", + new = "new" } export type ProfileData = { diff --git a/src/components/TagsInput/TagsInput.tsx b/src/components/TagsInput/TagsInput.tsx index 8cad03d..0034a5a 100644 --- a/src/components/TagsInput/TagsInput.tsx +++ b/src/components/TagsInput/TagsInput.tsx @@ -71,7 +71,7 @@ const TagsInput: React.FC = ({ (tagInput.current as HTMLInputElement).value .substring(1) .toLowerCase(), - status: TagStatus[3] + status: TagStatus.new } ]) setShowSuggestions(false) diff --git a/src/db/data-access/user/query.ts b/src/db/data-access/user/query.ts index ad9a4e5..95679ec 100644 --- a/src/db/data-access/user/query.ts +++ b/src/db/data-access/user/query.ts @@ -19,7 +19,6 @@ export async function CreateUser(data: InsertUser) { export async function SelectUserByExternalId(id: string) { return await db.query.usersTable.findFirst({ columns: { - id: true, first_name: true, last_name: true, email: true, @@ -32,7 +31,7 @@ export async function SelectUserByExternalId(id: string) { } export async function GetUsersFullName(ids: string[]) { - const uniqueIds = [...new Set(ids)] // Get unique IDs for the query + const uniqueIds = Array.from(new Set(ids)) // Get unique IDs for the query const users = await db.query.usersTable.findMany({ columns: { first_name: true, @@ -64,7 +63,6 @@ export async function FindUserWildCard(wildcard: string) { try { const users = await db.query.usersTable.findMany({ columns: { - id: true, first_name: true, last_name: true, email: true, diff --git a/src/db/migrations/0017_thin_titania.sql b/src/db/migrations/0017_thin_titania.sql new file mode 100644 index 0000000..ad51a89 --- /dev/null +++ b/src/db/migrations/0017_thin_titania.sql @@ -0,0 +1,51 @@ +CREATE TABLE `chats` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `channel_id` text NOT NULL, + `chat_slug` text NOT NULL, + `name` text, + `type` text, + `avatar` text, + `last_message` text, + `unread_count` integer DEFAULT 0 NOT NULL, + `is_group` integer DEFAULT 0 NOT NULL, + `updated_at` text, + `created_at` text DEFAULT CURRENT_TIMESTAMP, + `deleted_at` text +); +--> statement-breakpoint +CREATE TABLE `user_messages` ( + `user_id` text NOT NULL, + `message_id` integer NOT NULL +); +--> statement-breakpoint +DROP TABLE `chat`;--> statement-breakpoint +PRAGMA foreign_keys=OFF;--> statement-breakpoint +CREATE TABLE `__new_user_chats` ( + `user_id` text NOT NULL, + `chat_id` integer NOT NULL, + PRIMARY KEY(`user_id`, `chat_id`) +); +--> statement-breakpoint +INSERT INTO `__new_user_chats`("user_id", "chat_id") SELECT "user_id", "chat_id" FROM `user_chats`;--> statement-breakpoint +DROP TABLE `user_chats`;--> statement-breakpoint +ALTER TABLE `__new_user_chats` RENAME TO `user_chats`;--> statement-breakpoint +PRAGMA foreign_keys=ON;--> statement-breakpoint +DROP INDEX IF EXISTS "users_email_unique";--> statement-breakpoint +DROP INDEX IF EXISTS "users_external_auth_id_unique";--> statement-breakpoint +ALTER TABLE `messages` ALTER COLUMN "sender_id" TO "sender_id" text NOT NULL;--> statement-breakpoint +CREATE UNIQUE INDEX `users_email_unique` ON `users` (`email`);--> statement-breakpoint +CREATE UNIQUE INDEX `users_external_auth_id_unique` ON `users` (`external_auth_id`);--> statement-breakpoint +ALTER TABLE `messages` DROP COLUMN `timestamp`;--> statement-breakpoint +CREATE TABLE `__new_users` ( + `unique_id` text(36) PRIMARY KEY NOT NULL, + `first_name` text NOT NULL, + `last_name` text NOT NULL, + `email` text NOT NULL, + `external_auth_id` text NOT NULL, + `profile_url` text, + `meta` text +); +--> statement-breakpoint +INSERT INTO `__new_users`("unique_id", "first_name", "last_name", "email", "external_auth_id", "profile_url", "meta") SELECT "unique_id", "first_name", "last_name", "email", "external_auth_id", "profile_url", "meta" FROM `users`;--> statement-breakpoint +DROP TABLE `users`;--> statement-breakpoint +ALTER TABLE `__new_users` RENAME TO `users`; \ No newline at end of file diff --git a/src/db/migrations/0018_calm_magus.sql b/src/db/migrations/0018_calm_magus.sql new file mode 100644 index 0000000..2e8d890 --- /dev/null +++ b/src/db/migrations/0018_calm_magus.sql @@ -0,0 +1 @@ +ALTER TABLE `users` ADD `bio` text; \ No newline at end of file diff --git a/src/db/migrations/meta/0017_snapshot.json b/src/db/migrations/meta/0017_snapshot.json new file mode 100644 index 0000000..fa390dd --- /dev/null +++ b/src/db/migrations/meta/0017_snapshot.json @@ -0,0 +1,731 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "d44f7415-c271-4917-964a-e9950bbea9ad", + "prevId": "73d1c429-570d-419b-92f2-f576a2a3cc88", + "tables": { + "activities": { + "name": "activities", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "date": { + "name": "date", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "chats": { + "name": "chats", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "chat_slug": { + "name": "chat_slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "avatar": { + "name": "avatar", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_message": { + "name": "last_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "unread_count": { + "name": "unread_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "is_group": { + "name": "is_group", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "messages": { + "name": "messages", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "chat_id": { + "name": "chat_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sender_id": { + "name": "sender_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "recommendations": { + "name": "recommendations", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "recommender_id": { + "name": "recommender_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "receiver_id": { + "name": "receiver_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "rewards": { + "name": "rewards", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "badge_type": { + "name": "badge_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "tags": { + "name": "tags", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_activities": { + "name": "user_activities", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "activity_id": { + "name": "activity_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_chats": { + "name": "user_chats", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "chat_id": { + "name": "chat_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "user_chats_user_id_chat_id_pk": { + "columns": [ + "user_id", + "chat_id" + ], + "name": "user_chats_user_id_chat_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_contacts": { + "name": "user_contacts", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "contact_id": { + "name": "contact_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_requested": { + "name": "is_requested", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "is_accepted": { + "name": "is_accepted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "is_blocked": { + "name": "is_blocked", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "is_following": { + "name": "is_following", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "user_contacts_user_id_contact_id_pk": { + "columns": [ + "user_id", + "contact_id" + ], + "name": "user_contacts_user_id_contact_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_messages": { + "name": "user_messages", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message_id": { + "name": "message_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_rewards": { + "name": "user_rewards", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reward_id": { + "name": "reward_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_tags": { + "name": "user_tags", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "tag_id": { + "name": "tag_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "users": { + "name": "users", + "columns": { + "unique_id": { + "name": "unique_id", + "type": "text(36)", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "external_auth_id": { + "name": "external_auth_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "profile_url": { + "name": "profile_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta": { + "name": "meta", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "users_email_unique": { + "name": "users_email_unique", + "columns": [ + "email" + ], + "isUnique": true + }, + "users_external_auth_id_unique": { + "name": "users_external_auth_id_unique", + "columns": [ + "external_auth_id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/src/db/migrations/meta/0018_snapshot.json b/src/db/migrations/meta/0018_snapshot.json new file mode 100644 index 0000000..0435f82 --- /dev/null +++ b/src/db/migrations/meta/0018_snapshot.json @@ -0,0 +1,738 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "56bf540c-01e4-4c8a-b628-70f24e29ec78", + "prevId": "d44f7415-c271-4917-964a-e9950bbea9ad", + "tables": { + "activities": { + "name": "activities", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "date": { + "name": "date", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "chats": { + "name": "chats", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "chat_slug": { + "name": "chat_slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "avatar": { + "name": "avatar", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_message": { + "name": "last_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "unread_count": { + "name": "unread_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "is_group": { + "name": "is_group", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "messages": { + "name": "messages", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "chat_id": { + "name": "chat_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sender_id": { + "name": "sender_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "recommendations": { + "name": "recommendations", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "recommender_id": { + "name": "recommender_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "receiver_id": { + "name": "receiver_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "rewards": { + "name": "rewards", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "badge_type": { + "name": "badge_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "tags": { + "name": "tags", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_activities": { + "name": "user_activities", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "activity_id": { + "name": "activity_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_chats": { + "name": "user_chats", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "chat_id": { + "name": "chat_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "user_chats_user_id_chat_id_pk": { + "columns": [ + "user_id", + "chat_id" + ], + "name": "user_chats_user_id_chat_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_contacts": { + "name": "user_contacts", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "contact_id": { + "name": "contact_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_requested": { + "name": "is_requested", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "is_accepted": { + "name": "is_accepted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "is_blocked": { + "name": "is_blocked", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "is_following": { + "name": "is_following", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "deleted_at": { + "name": "deleted_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "user_contacts_user_id_contact_id_pk": { + "columns": [ + "user_id", + "contact_id" + ], + "name": "user_contacts_user_id_contact_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_messages": { + "name": "user_messages", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message_id": { + "name": "message_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_rewards": { + "name": "user_rewards", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reward_id": { + "name": "reward_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_tags": { + "name": "user_tags", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "tag_id": { + "name": "tag_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "users": { + "name": "users", + "columns": { + "unique_id": { + "name": "unique_id", + "type": "text(36)", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "external_auth_id": { + "name": "external_auth_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "profile_url": { + "name": "profile_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta": { + "name": "meta", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "bio": { + "name": "bio", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "users_email_unique": { + "name": "users_email_unique", + "columns": [ + "email" + ], + "isUnique": true + }, + "users_external_auth_id_unique": { + "name": "users_external_auth_id_unique", + "columns": [ + "external_auth_id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/src/db/migrations/meta/_journal.json b/src/db/migrations/meta/_journal.json index 60ef856..6e6574c 100644 --- a/src/db/migrations/meta/_journal.json +++ b/src/db/migrations/meta/_journal.json @@ -120,6 +120,20 @@ "when": 1736149590544, "tag": "0016_slow_morlocks", "breakpoints": true + }, + { + "idx": 17, + "version": "6", + "when": 1736266440800, + "tag": "0017_thin_titania", + "breakpoints": true + }, + { + "idx": 18, + "version": "6", + "when": 1736269431192, + "tag": "0018_calm_magus", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/db/schema.ts b/src/db/schema.ts index 6f88471..a4351f4 100644 --- a/src/db/schema.ts +++ b/src/db/schema.ts @@ -1,53 +1,50 @@ import { randomUUID } from "crypto" -import { relations, sql } from "drizzle-orm" +import { InferSelectModel, relations, sql } from "drizzle-orm" import { int, primaryKey, sqliteTable, text } from "drizzle-orm/sqlite-core" const timestamps = { - updated_at: text("updated_at"), + updated_at: text("updated_at").$onUpdateFn(() => sql`CURRENT_TIMESTAMP`), created_at: text("created_at").default(sql`CURRENT_TIMESTAMP`), deleted_at: text("deleted_at") } -export const usersTable = sqliteTable("users", { - id: int().primaryKey({ autoIncrement: true }), - first_name: text().notNull(), - last_name: text().notNull(), - email: text().notNull().unique(), - external_auth_id: text().notNull().unique(), - profile_url: text(), - unique_id: text("unique_id", { length: 36 }).$defaultFn(() => randomUUID()), - bio: text(), - meta: text() -}) - -export type InsertUser = typeof usersTable.$inferInsert -export type SelectUser = Omit - -export const userChatsTable = sqliteTable( - "user_chats", +export const usersTable = sqliteTable( + "users", { - user_id: text() - .notNull() - .references(() => usersTable.unique_id), - chat_id: int() - .notNull() - .references(() => chatTable.id) + unique_id: text("unique_id", { length: 36 }) + .primaryKey() + .$defaultFn(() => randomUUID()), + first_name: text().notNull(), + last_name: text().notNull(), + email: text().notNull().unique(), + external_auth_id: text().notNull().unique(), + profile_url: text(), + meta: text(), + bio: text() }, - (table) => ({ - pk: primaryKey({ columns: [table.user_id, table.chat_id] }) + (t) => ({ + pk: primaryKey({ columns: [t.unique_id] }) }) ) -export type InsertChat = typeof chatTable.$inferInsert -export type SelectChat = typeof chatTable.$inferSelect - export const usersRelations = relations(usersTable, ({ many }) => ({ - userChats: many(userChatsTable) + chats: many(userChatsTable, { + relationName: "UserChats" + }), + contacts: many(userContactsTable, { + relationName: "userToContact" + }) })) -export const chatTable = sqliteTable("chat", { +export type InsertUser = typeof usersTable.$inferInsert +export type SelectUser = Omit + +export const chatsTable = sqliteTable("chats", { id: int().primaryKey({ autoIncrement: true }), channel_id: text().notNull(), + chat_slug: text() + .notNull() + .$defaultFn(() => randomUUID()), name: text(), type: text(), avatar: text(), @@ -57,46 +54,90 @@ export const chatTable = sqliteTable("chat", { ...timestamps }) -export const chatRelations = relations(chatTable, ({ many }) => ({ - messages: many(messagesTable), - chatUsers: many(userChatsTable) +export const chatsRelations = relations(chatsTable, ({ many }) => ({ + messages: many(messagesTable, { + relationName: "messageToChat" + }), + users: many(userChatsTable, { + relationName: "ChatUsers" + }) })) -export type SelectChatWithRelation = typeof chatRelations.table.$inferSelect +export type InsertChat = typeof chatsTable.$inferInsert +export type SelectChat = InferSelectModel & { + messages?: SelectMessage[] + users?: SelectUserChat[] +} +export type SelectChatWithRelation = typeof chatsRelations -export const messagesTable = sqliteTable("messages", { - id: int().primaryKey({ autoIncrement: true }), - chat_id: int().notNull(), - type: text().notNull(), - sender_id: int().notNull(), - message: text().notNull(), - timestamp: int().notNull(), - ...timestamps -}) +export const messagesTable = sqliteTable( + "messages", + { + id: int().primaryKey({ autoIncrement: true }), + chat_id: int().notNull(), + type: text().notNull(), + sender_id: text().notNull(), + message: text().notNull(), + ...timestamps + }, + (t) => ({ + pk: primaryKey({ columns: [t.id] }) + }) +) export const messagesRelations = relations(messagesTable, ({ one }) => ({ - chat: one(chatTable, { + chat: one(chatsTable, { fields: [messagesTable.chat_id], - references: [chatTable.id] + references: [chatsTable.id], + relationName: "messageToChat" + }), + sender: one(usersTable, { + fields: [messagesTable.sender_id], + references: [usersTable.unique_id], + relationName: "messageToUser" }) })) export type InsertMessage = typeof messagesTable.$inferInsert export type SelectMessage = typeof messagesTable.$inferSelect +export const userChatsTable = sqliteTable( + "user_chats", + { + user_id: text().notNull(), + chat_id: int().notNull() + }, + (t) => ({ + pk: primaryKey({ columns: [t.user_id, t.chat_id] }) + }) +) + export const userChatsRelations = relations(userChatsTable, ({ one }) => ({ - chat: one(chatTable, { + chat: one(chatsTable, { fields: [userChatsTable.chat_id], - references: [chatTable.id] + references: [chatsTable.id], + relationName: "ChatUsers" }), user: one(usersTable, { fields: [userChatsTable.user_id], - references: [usersTable.unique_id] + references: [usersTable.unique_id], + relationName: "UserChats" }) })) export type InsertUserChat = typeof userChatsTable.$inferInsert -export type SelectUserChat = typeof userChatsTable.$inferSelect +export type SelectUserChat = typeof userChatsTable.$inferSelect & { + user?: SelectUser + chat?: SelectChat +} + +export const userMessagesTable = sqliteTable("user_messages", { + user_id: text().notNull(), + message_id: int().notNull() +}) + +export type InsertUserMessage = typeof userMessagesTable.$inferInsert +export type SelectUserMessage = typeof userMessagesTable.$inferSelect export const userContactsTable = sqliteTable( "user_contacts", @@ -109,23 +150,26 @@ export const userContactsTable = sqliteTable( is_following: int().notNull().default(0), ...timestamps }, - (table) => ({ - pk: primaryKey({ columns: [table.user_id, table.contact_id] }) + (t) => ({ + pk: primaryKey({ columns: [t.user_id, t.contact_id] }) }) ) -export const useContactsRelations = relations(userContactsTable, ({ one }) => ({ - user: one(usersTable, { - relationName: "userToContacts", - fields: [userContactsTable.user_id], - references: [usersTable.unique_id] - }), - contact: one(usersTable, { - relationName: "contactToUser", - fields: [userContactsTable.contact_id], - references: [usersTable.unique_id] +export const userContactsRelations = relations( + userContactsTable, + ({ one }) => ({ + user: one(usersTable, { + fields: [userContactsTable.user_id], + references: [usersTable.unique_id], + relationName: "userToUser" + }), + contact: one(usersTable, { + fields: [userContactsTable.contact_id], + references: [usersTable.unique_id], + relationName: "userToContact" + }) }) -})) +) export type InsertUserContact = typeof userContactsTable.$inferInsert export type SelectUserContact = typeof userContactsTable.$inferSelect diff --git a/src/server-actions/User/User.ts b/src/server-actions/User/User.ts index c4394fc..5e39ba6 100644 --- a/src/server-actions/User/User.ts +++ b/src/server-actions/User/User.ts @@ -63,7 +63,8 @@ export const SaveUserProfileAction = CreateServerAction( }) )) // delete tags - await DeleteUserTags(profileData.userId, profileData.deletedTagsIds) + profileData.deletedTagsIds.length && + (await DeleteUserTags(profileData.userId, profileData.deletedTagsIds)) return { success: true } From 57e60dc5ff9f1fe4805d7fa49218f1502e544000 Mon Sep 17 00:00:00 2001 From: Ammar Waheed Date: Wed, 8 Jan 2025 10:42:47 +0500 Subject: [PATCH 7/8] server action call optimizations --- .../Dashboard/profile/ProfileBioClient.tsx | 20 ++++------ .../Dashboard/profile/ProfileScreen.tsx | 5 ++- .../Dashboard/profile/profile-bio.tsx | 11 +++--- src/db/data-access/recommendation/query.ts | 27 +++++++++++-- src/db/data-access/user/query.ts | 39 ++----------------- .../Recommendations/Recommendations.ts | 14 +------ src/server-actions/User/User.ts | 20 +--------- 7 files changed, 47 insertions(+), 89 deletions(-) diff --git a/src/components/Dashboard/profile/ProfileBioClient.tsx b/src/components/Dashboard/profile/ProfileBioClient.tsx index a2a253c..a52b23f 100644 --- a/src/components/Dashboard/profile/ProfileBioClient.tsx +++ b/src/components/Dashboard/profile/ProfileBioClient.tsx @@ -5,7 +5,6 @@ import { Badge } from "../../ui/badge" import { useAtomValue, useSetAtom } from "jotai" import { profileStore } from "@/src/store/profile/profileStore" import { useServerAction } from "@/src/hooks/useServerAction" -import { GetBioForUserAction } from "@/src/server-actions/User/User" import { GetTagsForUserAction } from "@/src/server-actions/Tag/Tag" import { useEffect } from "react" import { Tag, TagStatus } from "./types/profile-types.d" @@ -15,11 +14,13 @@ import { LoaderSizes } from "../../common/Loader/types/loader-types.d" type ProfileBioClientProps = { editable?: boolean userId: string + userBio: string } const ProfileBioClient: React.FC = ({ editable = true, - userId + userId, + userBio }) => { const setUserBio = useSetAtom(profileStore.bio) const setUserSkills = useSetAtom(profileStore.skills) @@ -28,8 +29,6 @@ const ProfileBioClient: React.FC = ({ const interests = useAtomValue(profileStore.interests) const bio = useAtomValue(profileStore.bio) - const [getBioLoading, bioData, getBioError, getBio] = - useServerAction(GetBioForUserAction) const [getTagsLoading, tagsData, getTagsError, getTags] = useServerAction(GetTagsForUserAction) @@ -56,21 +55,16 @@ const ProfileBioClient: React.FC = ({ useEffect(() => { if (userId) { - getBio(userId) getTags(userId) } }, [userId]) useEffect(() => { - setUserBio(bioData?.data as string) - }, [bioData]) + setUserBio(userBio) + }, [userBio]) - return getTagsLoading || getBioLoading ? ( -
    + return getTagsLoading ? ( +
    ) : ( diff --git a/src/components/Dashboard/profile/ProfileScreen.tsx b/src/components/Dashboard/profile/ProfileScreen.tsx index d1cece7..0c1409a 100644 --- a/src/components/Dashboard/profile/ProfileScreen.tsx +++ b/src/components/Dashboard/profile/ProfileScreen.tsx @@ -66,7 +66,10 @@ export default async function ProfileScreen({ tab }: ProfileScreenProps) { */} - + diff --git a/src/components/Dashboard/profile/profile-bio.tsx b/src/components/Dashboard/profile/profile-bio.tsx index a8e2e58..8f551f6 100644 --- a/src/components/Dashboard/profile/profile-bio.tsx +++ b/src/components/Dashboard/profile/profile-bio.tsx @@ -1,19 +1,20 @@ -import { FetchUserRecommendationsAction } from "@/src/server-actions/Recommendations/Recommendations" +import { GetUserRecommendationsAction } from "@/src/server-actions/Recommendations/Recommendations" import { Card, CardContent } from "../../ui/card" import ProfileBioClient from "./ProfileBioClient" type ProfileBioProps = { userId: string + userBio: string } -const ProfileBio: React.FC = async ({ userId }) => { - const recommendations = await FetchUserRecommendationsAction(userId) +const ProfileBio: React.FC = async ({ userId, userBio }) => { + const recommendations = await GetUserRecommendationsAction(userId) return ( <> - +

    Recommendations

      @@ -23,7 +24,7 @@ const ProfileBio: React.FC = async ({ userId }) => { "{recommendation.content}"

      - - {recommendation.recommender} + - {recommendation.recommender_full_name}

      ))} diff --git a/src/db/data-access/recommendation/query.ts b/src/db/data-access/recommendation/query.ts index 5f3589b..1d18e27 100644 --- a/src/db/data-access/recommendation/query.ts +++ b/src/db/data-access/recommendation/query.ts @@ -1,11 +1,32 @@ -import { recommendationsTable } from "./../../schema" +import { recommendationsTable, usersTable } from "./../../schema" import { db } from "../.." import { eq } from "drizzle-orm" export const GetRecommendations = async (id: string) => { const results = await db - .select() + .select({ + id: recommendationsTable.id, + receiver_id: recommendationsTable.receiver_id, + recommender_id: recommendationsTable.recommender_id, + content: recommendationsTable.content, + created_at: recommendationsTable.created_at, + recommender: { + first_name: usersTable.first_name, + last_name: usersTable.last_name + } + }) .from(recommendationsTable) + .innerJoin( + usersTable, + eq(recommendationsTable.recommender_id, usersTable.external_auth_id) + ) .where(eq(recommendationsTable.receiver_id, id)) - return results ?? [] + return ( + results.map((result) => ({ + ...result, + recommender_full_name: result.recommender + ? `${result.recommender.first_name} ${result.recommender.last_name}` + : "" + })) ?? [] + ) } diff --git a/src/db/data-access/user/query.ts b/src/db/data-access/user/query.ts index 95679ec..cf3bdd4 100644 --- a/src/db/data-access/user/query.ts +++ b/src/db/data-access/user/query.ts @@ -1,17 +1,7 @@ -import { eq, inArray, like } from "drizzle-orm" +import { eq, like } from "drizzle-orm" import { db } from "../.." import { InsertUser, usersTable } from "../../schema" -export const userTableColSelect = { - id: true, - first_name: true, - last_name: true, - email: true, - external_auth_id: true, - profile_url: true, - unique_id: true -} - export async function CreateUser(data: InsertUser) { await db.insert(usersTable).values(data) } @@ -24,29 +14,13 @@ export async function SelectUserByExternalId(id: string) { email: true, external_auth_id: true, profile_url: true, - unique_id: true + unique_id: true, + bio: true }, where: eq(usersTable.external_auth_id, id) }) } -export async function GetUsersFullName(ids: string[]) { - const uniqueIds = Array.from(new Set(ids)) // Get unique IDs for the query - const users = await db.query.usersTable.findMany({ - columns: { - first_name: true, - last_name: true, - external_auth_id: true // Need this to match with input ids - }, - where: (usersTable) => inArray(usersTable.external_auth_id, uniqueIds) - }) - // Map over original ids array to maintain order and duplicates - return ids.map((id) => { - const user = users.find((u) => u.external_auth_id === id) - return user ? `${user.first_name} ${user.last_name}` : "" - }) -} - export async function SelectUserByEmail(email: string) { return await db.query.usersTable.findFirst({ where: eq(usersTable.email, email) @@ -88,10 +62,3 @@ export async function UpdateUserBio(userId: string, bio: string) { .set({ bio }) .where(eq(usersTable.external_auth_id, userId)) } - -export const GetUserBio = async (userId: string) => { - const user = await db.query.usersTable.findFirst({ - where: eq(usersTable.external_auth_id, userId) - }) - return user?.bio -} diff --git a/src/server-actions/Recommendations/Recommendations.ts b/src/server-actions/Recommendations/Recommendations.ts index bfc4805..4156733 100644 --- a/src/server-actions/Recommendations/Recommendations.ts +++ b/src/server-actions/Recommendations/Recommendations.ts @@ -1,23 +1,13 @@ "use server" -import { - GetUsersFullName -} from "../../db/data-access/user/query" import { GetRecommendations } from "../../db/data-access/recommendation/query" import { CreateServerAction } from ".." -export const FetchUserRecommendationsAction = CreateServerAction( +export const GetUserRecommendationsAction = CreateServerAction( true, async (externalAuthId: string) => { try { - const recommendations = await GetRecommendations(externalAuthId) - const RecommenderNames = await GetUsersFullName( - recommendations.map((recommendation) => recommendation.recommender_id) - ) - return recommendations.map((recommendation, i) => ({ - ...recommendation, - recommender: RecommenderNames[i] - })) + return await GetRecommendations(externalAuthId) } catch (error) { console.error("Error fetching recommendations:", error) throw error diff --git a/src/server-actions/User/User.ts b/src/server-actions/User/User.ts index 5e39ba6..40f5504 100644 --- a/src/server-actions/User/User.ts +++ b/src/server-actions/User/User.ts @@ -1,6 +1,6 @@ "use server" -import { GetUserBio, UpdateUserBio } from "@/src/db/data-access/user/query" +import { UpdateUserBio } from "@/src/db/data-access/user/query" import { CreateServerAction } from ".." import { AddTag } from "@/src/db/data-access/tag/query" import { AddUserTag, DeleteUserTags } from "@/src/db/data-access/tag/query" @@ -23,24 +23,6 @@ export const UpdateBioForUserAction = CreateServerAction( } ) -export const GetBioForUserAction = CreateServerAction( - true, - async (userId: string) => { - try { - const user = await GetUserBio(userId) - return { - success: true, - data: user - } - } catch (error) { - return { - success: false, - error: error - } - } - } -) - export const SaveUserProfileAction = CreateServerAction( true, async (profileData: ProfileData) => { From ea8c0cbd29650981ec47f55460069f5705edfcb9 Mon Sep 17 00:00:00 2001 From: Usama Tariq Date: Thu, 9 Jan 2025 20:05:58 +0500 Subject: [PATCH 8/8] migration fixes and remove of use external auth id --- src/app/(dashboard)/profile/[id]/page.tsx | 99 +-- .../Dashboard/profile/ProfileScreen.tsx | 6 +- .../Dashboard/profile/edit-profile-modal.tsx | 2 +- .../Dashboard/profile/profile-bio.tsx | 5 +- src/db/data-access/recommendation/query.ts | 2 +- src/db/data-access/user/query.ts | 2 +- src/db/migrations/0016_crazy_silver_sable.sql | 59 ++ src/db/migrations/0016_slow_morlocks.sql | 99 --- src/db/migrations/0017_thin_titania.sql | 51 -- src/db/migrations/0018_calm_magus.sql | 1 - src/db/migrations/meta/0016_snapshot.json | 96 +-- src/db/migrations/meta/0017_snapshot.json | 731 ----------------- src/db/migrations/meta/0018_snapshot.json | 738 ------------------ src/db/migrations/meta/_journal.json | 18 +- .../Recommendations/Recommendations.ts | 4 +- 15 files changed, 146 insertions(+), 1767 deletions(-) create mode 100644 src/db/migrations/0016_crazy_silver_sable.sql delete mode 100644 src/db/migrations/0016_slow_morlocks.sql delete mode 100644 src/db/migrations/0017_thin_titania.sql delete mode 100644 src/db/migrations/0018_calm_magus.sql delete mode 100644 src/db/migrations/meta/0017_snapshot.json delete mode 100644 src/db/migrations/meta/0018_snapshot.json diff --git a/src/app/(dashboard)/profile/[id]/page.tsx b/src/app/(dashboard)/profile/[id]/page.tsx index 1e611c3..ccd3b6c 100644 --- a/src/app/(dashboard)/profile/[id]/page.tsx +++ b/src/app/(dashboard)/profile/[id]/page.tsx @@ -16,36 +16,6 @@ import { FindUserByUniqueIdAction } from "@/src/server-actions/User/FindUserByUn import { CalendarIcon, StarIcon, TrophyIcon, UserIcon } from "lucide-react" import Link from "next/link" -const skillTags = ["React", "Next.js", "TypeScript", "UI/UX", "Node.js"] -const interests = ["Web Development", "AI", "Open Source", "Tech Writing"] -const recommendations = [ - { - name: "Jane Doe", - text: "An exceptional developer with a keen eye for detail.", - }, - { name: "John Smith", text: "Always delivers high-quality work on time." }, -] -const rewards = [ - { - title: "Top Contributor", - description: "Awarded for outstanding contributions to the team", - }, - { - title: "Innovation Champion", - description: "Recognized for implementing creative solutions", - }, -] -const activities = [ - { - date: "2023-04-01", - description: "Completed the 'Advanced React Patterns' course", - }, - { - date: "2023-03-15", - description: "Contributed to open-source project 'awesome-ui-components'", - }, -] - interface ProfileScreenProps { params:{ id: string @@ -80,56 +50,49 @@ export default async function ProfileScreen({ params: { id }, searchParams:{tab}
    - + - - - - Bio/Basic - - - - - - Rewards - - - - - - - Activity - - - - - - - Calendar - - + + + + Bio/Basic + + + + + + Rewards + + + + + + Activity + + + {/* + + + Calendar + + */} - + - + - + {/* - + */}
) diff --git a/src/components/Dashboard/profile/ProfileScreen.tsx b/src/components/Dashboard/profile/ProfileScreen.tsx index 0c1409a..1a7ef29 100644 --- a/src/components/Dashboard/profile/ProfileScreen.tsx +++ b/src/components/Dashboard/profile/ProfileScreen.tsx @@ -67,15 +67,15 @@ export default async function ProfileScreen({ tab }: ProfileScreenProps) { - + - + {/* diff --git a/src/components/Dashboard/profile/edit-profile-modal.tsx b/src/components/Dashboard/profile/edit-profile-modal.tsx index 7dafe82..6776221 100644 --- a/src/components/Dashboard/profile/edit-profile-modal.tsx +++ b/src/components/Dashboard/profile/edit-profile-modal.tsx @@ -93,7 +93,7 @@ const EditProfileModal: React.FC = () => { ) .map((interest) => interest.id as number) const updatedProfileData: ProfileData = { - userId: user?.external_auth_id as string, + userId: user?.unique_id as string, bio: editedBio ? editedBio : bio, newTags: [ ...skills diff --git a/src/components/Dashboard/profile/profile-bio.tsx b/src/components/Dashboard/profile/profile-bio.tsx index 8f551f6..61610df 100644 --- a/src/components/Dashboard/profile/profile-bio.tsx +++ b/src/components/Dashboard/profile/profile-bio.tsx @@ -5,16 +5,17 @@ import ProfileBioClient from "./ProfileBioClient" type ProfileBioProps = { userId: string userBio: string + editable?: boolean } -const ProfileBio: React.FC = async ({ userId, userBio }) => { +const ProfileBio: React.FC = async ({ userId, userBio, editable }) => { const recommendations = await GetUserRecommendationsAction(userId) return ( <> - +

Recommendations

    diff --git a/src/db/data-access/recommendation/query.ts b/src/db/data-access/recommendation/query.ts index 1d18e27..786c8a1 100644 --- a/src/db/data-access/recommendation/query.ts +++ b/src/db/data-access/recommendation/query.ts @@ -18,7 +18,7 @@ export const GetRecommendations = async (id: string) => { .from(recommendationsTable) .innerJoin( usersTable, - eq(recommendationsTable.recommender_id, usersTable.external_auth_id) + eq(recommendationsTable.recommender_id, usersTable.unique_id) ) .where(eq(recommendationsTable.receiver_id, id)) return ( diff --git a/src/db/data-access/user/query.ts b/src/db/data-access/user/query.ts index cf3bdd4..4c3f2c7 100644 --- a/src/db/data-access/user/query.ts +++ b/src/db/data-access/user/query.ts @@ -60,5 +60,5 @@ export async function UpdateUserBio(userId: string, bio: string) { await db .update(usersTable) .set({ bio }) - .where(eq(usersTable.external_auth_id, userId)) + .where(eq(usersTable.unique_id, userId)) } diff --git a/src/db/migrations/0016_crazy_silver_sable.sql b/src/db/migrations/0016_crazy_silver_sable.sql new file mode 100644 index 0000000..ac1341f --- /dev/null +++ b/src/db/migrations/0016_crazy_silver_sable.sql @@ -0,0 +1,59 @@ +CREATE TABLE `activities` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `title` text NOT NULL, + `date` text NOT NULL, + `description` text NOT NULL, + `type` text NOT NULL, + `updated_at` text, + `created_at` text DEFAULT CURRENT_TIMESTAMP, + `deleted_at` text +); +--> statement-breakpoint +CREATE TABLE `recommendations` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `content` text NOT NULL, + `recommender_id` text NOT NULL, + `receiver_id` text NOT NULL, + `updated_at` text, + `created_at` text DEFAULT CURRENT_TIMESTAMP, + `deleted_at` text +); +--> statement-breakpoint +CREATE TABLE `rewards` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `title` text NOT NULL, + `description` text NOT NULL, + `badge_type` text NOT NULL, + `updated_at` text, + `created_at` text DEFAULT CURRENT_TIMESTAMP, + `deleted_at` text +); +--> statement-breakpoint +CREATE TABLE `tags` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `name` text NOT NULL, + `type` text NOT NULL, + `updated_at` text, + `created_at` text DEFAULT CURRENT_TIMESTAMP, + `deleted_at` text +); +--> statement-breakpoint +CREATE TABLE `user_activities` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `user_id` text NOT NULL, + `activity_id` integer NOT NULL +); +--> statement-breakpoint +CREATE TABLE `user_rewards` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `user_id` text NOT NULL, + `reward_id` integer NOT NULL +); +--> statement-breakpoint +CREATE TABLE `user_tags` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `user_id` text NOT NULL, + `tag_id` integer NOT NULL +); +--> statement-breakpoint +ALTER TABLE `users` ADD `bio` text; \ No newline at end of file diff --git a/src/db/migrations/0016_slow_morlocks.sql b/src/db/migrations/0016_slow_morlocks.sql deleted file mode 100644 index a9d0e2f..0000000 --- a/src/db/migrations/0016_slow_morlocks.sql +++ /dev/null @@ -1,99 +0,0 @@ -CREATE TABLE `activities` ( - `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, - `title` text NOT NULL, - `date` text NOT NULL, - `description` text NOT NULL, - `type` text NOT NULL, - `updated_at` text, - `created_at` text DEFAULT CURRENT_TIMESTAMP, - `deleted_at` text -); ---> statement-breakpoint -CREATE TABLE `chat` ( - `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, - `channel_id` text NOT NULL, - `name` text, - `type` text, - `avatar` text, - `last_message` text, - `unread_count` integer DEFAULT 0 NOT NULL, - `is_group` integer DEFAULT 0 NOT NULL, - `updated_at` text, - `created_at` text DEFAULT CURRENT_TIMESTAMP, - `deleted_at` text -); ---> statement-breakpoint -CREATE TABLE `recommendations` ( - `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, - `content` text NOT NULL, - `recommender_id` text NOT NULL, - `receiver_id` text NOT NULL, - `updated_at` text, - `created_at` text DEFAULT CURRENT_TIMESTAMP, - `deleted_at` text -); ---> statement-breakpoint -CREATE TABLE `rewards` ( - `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, - `title` text NOT NULL, - `description` text NOT NULL, - `badge_type` text NOT NULL, - `updated_at` text, - `created_at` text DEFAULT CURRENT_TIMESTAMP, - `deleted_at` text -); ---> statement-breakpoint -CREATE TABLE `tags` ( - `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, - `name` text NOT NULL, - `type` text NOT NULL, - `updated_at` text, - `created_at` text DEFAULT CURRENT_TIMESTAMP, - `deleted_at` text -); ---> statement-breakpoint -CREATE TABLE `user_activities` ( - `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, - `user_id` text NOT NULL, - `activity_id` integer NOT NULL -); ---> statement-breakpoint -CREATE TABLE `user_rewards` ( - `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, - `user_id` text NOT NULL, - `reward_id` integer NOT NULL -); ---> statement-breakpoint -CREATE TABLE `user_tags` ( - `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, - `user_id` text NOT NULL, - `tag_id` integer NOT NULL -); ---> statement-breakpoint -DROP TABLE `chats`;--> statement-breakpoint -DROP TABLE `user_messages`;--> statement-breakpoint -DROP INDEX IF EXISTS "users_email_unique";--> statement-breakpoint -DROP INDEX IF EXISTS "users_external_auth_id_unique";--> statement-breakpoint -ALTER TABLE `messages` ALTER COLUMN "sender_id" TO "sender_id" integer NOT NULL;--> statement-breakpoint -CREATE UNIQUE INDEX `users_email_unique` ON `users` (`email`);--> statement-breakpoint -CREATE UNIQUE INDEX `users_external_auth_id_unique` ON `users` (`external_auth_id`);--> statement-breakpoint -ALTER TABLE `messages` ADD `timestamp` integer NOT NULL;--> statement-breakpoint -PRAGMA foreign_keys=OFF;--> statement-breakpoint -CREATE TABLE `__new_users` ( - `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, - `first_name` text NOT NULL, - `last_name` text NOT NULL, - `email` text NOT NULL, - `external_auth_id` text NOT NULL, - `profile_url` text, - `unique_id` text(36), - `bio` text, - `meta` text -); ---> statement-breakpoint -INSERT INTO `__new_users`("id", "first_name", "last_name", "email", "external_auth_id", "profile_url", "unique_id", "bio", "meta") SELECT "id", "first_name", "last_name", "email", "external_auth_id", "profile_url", "unique_id", "bio", "meta" FROM `users`;--> statement-breakpoint -DROP TABLE `users`;--> statement-breakpoint -ALTER TABLE `__new_users` RENAME TO `users`;--> statement-breakpoint -PRAGMA foreign_keys=ON;--> statement-breakpoint -ALTER TABLE `user_chats` ALTER COLUMN "user_id" TO "user_id" text NOT NULL REFERENCES users(unique_id) ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE `user_chats` ALTER COLUMN "chat_id" TO "chat_id" integer NOT NULL REFERENCES chat(id) ON DELETE no action ON UPDATE no action; \ No newline at end of file diff --git a/src/db/migrations/0017_thin_titania.sql b/src/db/migrations/0017_thin_titania.sql deleted file mode 100644 index ad51a89..0000000 --- a/src/db/migrations/0017_thin_titania.sql +++ /dev/null @@ -1,51 +0,0 @@ -CREATE TABLE `chats` ( - `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, - `channel_id` text NOT NULL, - `chat_slug` text NOT NULL, - `name` text, - `type` text, - `avatar` text, - `last_message` text, - `unread_count` integer DEFAULT 0 NOT NULL, - `is_group` integer DEFAULT 0 NOT NULL, - `updated_at` text, - `created_at` text DEFAULT CURRENT_TIMESTAMP, - `deleted_at` text -); ---> statement-breakpoint -CREATE TABLE `user_messages` ( - `user_id` text NOT NULL, - `message_id` integer NOT NULL -); ---> statement-breakpoint -DROP TABLE `chat`;--> statement-breakpoint -PRAGMA foreign_keys=OFF;--> statement-breakpoint -CREATE TABLE `__new_user_chats` ( - `user_id` text NOT NULL, - `chat_id` integer NOT NULL, - PRIMARY KEY(`user_id`, `chat_id`) -); ---> statement-breakpoint -INSERT INTO `__new_user_chats`("user_id", "chat_id") SELECT "user_id", "chat_id" FROM `user_chats`;--> statement-breakpoint -DROP TABLE `user_chats`;--> statement-breakpoint -ALTER TABLE `__new_user_chats` RENAME TO `user_chats`;--> statement-breakpoint -PRAGMA foreign_keys=ON;--> statement-breakpoint -DROP INDEX IF EXISTS "users_email_unique";--> statement-breakpoint -DROP INDEX IF EXISTS "users_external_auth_id_unique";--> statement-breakpoint -ALTER TABLE `messages` ALTER COLUMN "sender_id" TO "sender_id" text NOT NULL;--> statement-breakpoint -CREATE UNIQUE INDEX `users_email_unique` ON `users` (`email`);--> statement-breakpoint -CREATE UNIQUE INDEX `users_external_auth_id_unique` ON `users` (`external_auth_id`);--> statement-breakpoint -ALTER TABLE `messages` DROP COLUMN `timestamp`;--> statement-breakpoint -CREATE TABLE `__new_users` ( - `unique_id` text(36) PRIMARY KEY NOT NULL, - `first_name` text NOT NULL, - `last_name` text NOT NULL, - `email` text NOT NULL, - `external_auth_id` text NOT NULL, - `profile_url` text, - `meta` text -); ---> statement-breakpoint -INSERT INTO `__new_users`("unique_id", "first_name", "last_name", "email", "external_auth_id", "profile_url", "meta") SELECT "unique_id", "first_name", "last_name", "email", "external_auth_id", "profile_url", "meta" FROM `users`;--> statement-breakpoint -DROP TABLE `users`;--> statement-breakpoint -ALTER TABLE `__new_users` RENAME TO `users`; \ No newline at end of file diff --git a/src/db/migrations/0018_calm_magus.sql b/src/db/migrations/0018_calm_magus.sql deleted file mode 100644 index 2e8d890..0000000 --- a/src/db/migrations/0018_calm_magus.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE `users` ADD `bio` text; \ No newline at end of file diff --git a/src/db/migrations/meta/0016_snapshot.json b/src/db/migrations/meta/0016_snapshot.json index 15ac720..f9b1e8e 100644 --- a/src/db/migrations/meta/0016_snapshot.json +++ b/src/db/migrations/meta/0016_snapshot.json @@ -1,7 +1,7 @@ { "version": "6", "dialect": "sqlite", - "id": "73d1c429-570d-419b-92f2-f576a2a3cc88", + "id": "5d0c85db-057f-4087-af9b-71229f94d141", "prevId": "7b8ae6d9-e108-43af-8e92-8576a9e73faa", "tables": { "activities": { @@ -71,8 +71,8 @@ "uniqueConstraints": {}, "checkConstraints": {} }, - "chat": { - "name": "chat", + "chats": { + "name": "chats", "columns": { "id": { "name": "id", @@ -88,6 +88,13 @@ "notNull": true, "autoincrement": false }, + "chat_slug": { + "name": "chat_slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, "name": { "name": "name", "type": "text", @@ -187,7 +194,7 @@ }, "sender_id": { "name": "sender_id", - "type": "integer", + "type": "text", "primaryKey": false, "notNull": true, "autoincrement": false @@ -199,13 +206,6 @@ "notNull": true, "autoincrement": false }, - "timestamp": { - "name": "timestamp", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, "updated_at": { "name": "updated_at", "type": "text", @@ -458,34 +458,7 @@ } }, "indexes": {}, - "foreignKeys": { - "user_chats_user_id_users_unique_id_fk": { - "name": "user_chats_user_id_users_unique_id_fk", - "tableFrom": "user_chats", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "unique_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "user_chats_chat_id_chat_id_fk": { - "name": "user_chats_chat_id_chat_id_fk", - "tableFrom": "user_chats", - "tableTo": "chat", - "columnsFrom": [ - "chat_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, + "foreignKeys": {}, "compositePrimaryKeys": { "user_chats_user_id_chat_id_pk": { "columns": [ @@ -584,6 +557,30 @@ "uniqueConstraints": {}, "checkConstraints": {} }, + "user_messages": { + "name": "user_messages", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message_id": { + "name": "message_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, "user_rewards": { "name": "user_rewards", "columns": { @@ -649,12 +646,12 @@ "users": { "name": "users", "columns": { - "id": { - "name": "id", - "type": "integer", + "unique_id": { + "name": "unique_id", + "type": "text(36)", "primaryKey": true, "notNull": true, - "autoincrement": true + "autoincrement": false }, "first_name": { "name": "first_name", @@ -691,9 +688,9 @@ "notNull": false, "autoincrement": false }, - "unique_id": { - "name": "unique_id", - "type": "text(36)", + "meta": { + "name": "meta", + "type": "text", "primaryKey": false, "notNull": false, "autoincrement": false @@ -704,13 +701,6 @@ "primaryKey": false, "notNull": false, "autoincrement": false - }, - "meta": { - "name": "meta", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false } }, "indexes": { diff --git a/src/db/migrations/meta/0017_snapshot.json b/src/db/migrations/meta/0017_snapshot.json deleted file mode 100644 index fa390dd..0000000 --- a/src/db/migrations/meta/0017_snapshot.json +++ /dev/null @@ -1,731 +0,0 @@ -{ - "version": "6", - "dialect": "sqlite", - "id": "d44f7415-c271-4917-964a-e9950bbea9ad", - "prevId": "73d1c429-570d-419b-92f2-f576a2a3cc88", - "tables": { - "activities": { - "name": "activities", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "date": { - "name": "date", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "updated_at": { - "name": "updated_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP" - }, - "deleted_at": { - "name": "deleted_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "chats": { - "name": "chats", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "channel_id": { - "name": "channel_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "chat_slug": { - "name": "chat_slug", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "avatar": { - "name": "avatar", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "last_message": { - "name": "last_message", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "unread_count": { - "name": "unread_count", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "is_group": { - "name": "is_group", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "updated_at": { - "name": "updated_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP" - }, - "deleted_at": { - "name": "deleted_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "messages": { - "name": "messages", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "chat_id": { - "name": "chat_id", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "sender_id": { - "name": "sender_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "message": { - "name": "message", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "updated_at": { - "name": "updated_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP" - }, - "deleted_at": { - "name": "deleted_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "recommendations": { - "name": "recommendations", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "content": { - "name": "content", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "recommender_id": { - "name": "recommender_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "receiver_id": { - "name": "receiver_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "updated_at": { - "name": "updated_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP" - }, - "deleted_at": { - "name": "deleted_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "rewards": { - "name": "rewards", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "badge_type": { - "name": "badge_type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "updated_at": { - "name": "updated_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP" - }, - "deleted_at": { - "name": "deleted_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "tags": { - "name": "tags", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "updated_at": { - "name": "updated_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP" - }, - "deleted_at": { - "name": "deleted_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "user_activities": { - "name": "user_activities", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "activity_id": { - "name": "activity_id", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "user_chats": { - "name": "user_chats", - "columns": { - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "chat_id": { - "name": "chat_id", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_chats_user_id_chat_id_pk": { - "columns": [ - "user_id", - "chat_id" - ], - "name": "user_chats_user_id_chat_id_pk" - } - }, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "user_contacts": { - "name": "user_contacts", - "columns": { - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "contact_id": { - "name": "contact_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "is_requested": { - "name": "is_requested", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "is_accepted": { - "name": "is_accepted", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "is_blocked": { - "name": "is_blocked", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "is_following": { - "name": "is_following", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "updated_at": { - "name": "updated_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP" - }, - "deleted_at": { - "name": "deleted_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_contacts_user_id_contact_id_pk": { - "columns": [ - "user_id", - "contact_id" - ], - "name": "user_contacts_user_id_contact_id_pk" - } - }, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "user_messages": { - "name": "user_messages", - "columns": { - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "message_id": { - "name": "message_id", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "user_rewards": { - "name": "user_rewards", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reward_id": { - "name": "reward_id", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "user_tags": { - "name": "user_tags", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "tag_id": { - "name": "tag_id", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "users": { - "name": "users", - "columns": { - "unique_id": { - "name": "unique_id", - "type": "text(36)", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "first_name": { - "name": "first_name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "last_name": { - "name": "last_name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "external_auth_id": { - "name": "external_auth_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "profile_url": { - "name": "profile_url", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "meta": { - "name": "meta", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "users_email_unique": { - "name": "users_email_unique", - "columns": [ - "email" - ], - "isUnique": true - }, - "users_external_auth_id_unique": { - "name": "users_external_auth_id_unique", - "columns": [ - "external_auth_id" - ], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - } - }, - "views": {}, - "enums": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "indexes": {} - } -} \ No newline at end of file diff --git a/src/db/migrations/meta/0018_snapshot.json b/src/db/migrations/meta/0018_snapshot.json deleted file mode 100644 index 0435f82..0000000 --- a/src/db/migrations/meta/0018_snapshot.json +++ /dev/null @@ -1,738 +0,0 @@ -{ - "version": "6", - "dialect": "sqlite", - "id": "56bf540c-01e4-4c8a-b628-70f24e29ec78", - "prevId": "d44f7415-c271-4917-964a-e9950bbea9ad", - "tables": { - "activities": { - "name": "activities", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "date": { - "name": "date", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "updated_at": { - "name": "updated_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP" - }, - "deleted_at": { - "name": "deleted_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "chats": { - "name": "chats", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "channel_id": { - "name": "channel_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "chat_slug": { - "name": "chat_slug", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "avatar": { - "name": "avatar", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "last_message": { - "name": "last_message", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "unread_count": { - "name": "unread_count", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "is_group": { - "name": "is_group", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "updated_at": { - "name": "updated_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP" - }, - "deleted_at": { - "name": "deleted_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "messages": { - "name": "messages", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "chat_id": { - "name": "chat_id", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "sender_id": { - "name": "sender_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "message": { - "name": "message", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "updated_at": { - "name": "updated_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP" - }, - "deleted_at": { - "name": "deleted_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "recommendations": { - "name": "recommendations", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "content": { - "name": "content", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "recommender_id": { - "name": "recommender_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "receiver_id": { - "name": "receiver_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "updated_at": { - "name": "updated_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP" - }, - "deleted_at": { - "name": "deleted_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "rewards": { - "name": "rewards", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "badge_type": { - "name": "badge_type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "updated_at": { - "name": "updated_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP" - }, - "deleted_at": { - "name": "deleted_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "tags": { - "name": "tags", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "updated_at": { - "name": "updated_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP" - }, - "deleted_at": { - "name": "deleted_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "user_activities": { - "name": "user_activities", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "activity_id": { - "name": "activity_id", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "user_chats": { - "name": "user_chats", - "columns": { - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "chat_id": { - "name": "chat_id", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_chats_user_id_chat_id_pk": { - "columns": [ - "user_id", - "chat_id" - ], - "name": "user_chats_user_id_chat_id_pk" - } - }, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "user_contacts": { - "name": "user_contacts", - "columns": { - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "contact_id": { - "name": "contact_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "is_requested": { - "name": "is_requested", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "is_accepted": { - "name": "is_accepted", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "is_blocked": { - "name": "is_blocked", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "is_following": { - "name": "is_following", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "updated_at": { - "name": "updated_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "CURRENT_TIMESTAMP" - }, - "deleted_at": { - "name": "deleted_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "user_contacts_user_id_contact_id_pk": { - "columns": [ - "user_id", - "contact_id" - ], - "name": "user_contacts_user_id_contact_id_pk" - } - }, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "user_messages": { - "name": "user_messages", - "columns": { - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "message_id": { - "name": "message_id", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "user_rewards": { - "name": "user_rewards", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "reward_id": { - "name": "reward_id", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "user_tags": { - "name": "user_tags", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "tag_id": { - "name": "tag_id", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "users": { - "name": "users", - "columns": { - "unique_id": { - "name": "unique_id", - "type": "text(36)", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "first_name": { - "name": "first_name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "last_name": { - "name": "last_name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "external_auth_id": { - "name": "external_auth_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "profile_url": { - "name": "profile_url", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "meta": { - "name": "meta", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "bio": { - "name": "bio", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "users_email_unique": { - "name": "users_email_unique", - "columns": [ - "email" - ], - "isUnique": true - }, - "users_external_auth_id_unique": { - "name": "users_external_auth_id_unique", - "columns": [ - "external_auth_id" - ], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - } - }, - "views": {}, - "enums": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "indexes": {} - } -} \ No newline at end of file diff --git a/src/db/migrations/meta/_journal.json b/src/db/migrations/meta/_journal.json index 6e6574c..98dd63a 100644 --- a/src/db/migrations/meta/_journal.json +++ b/src/db/migrations/meta/_journal.json @@ -117,22 +117,8 @@ { "idx": 16, "version": "6", - "when": 1736149590544, - "tag": "0016_slow_morlocks", - "breakpoints": true - }, - { - "idx": 17, - "version": "6", - "when": 1736266440800, - "tag": "0017_thin_titania", - "breakpoints": true - }, - { - "idx": 18, - "version": "6", - "when": 1736269431192, - "tag": "0018_calm_magus", + "when": 1736433761973, + "tag": "0016_crazy_silver_sable", "breakpoints": true } ] diff --git a/src/server-actions/Recommendations/Recommendations.ts b/src/server-actions/Recommendations/Recommendations.ts index 4156733..6553bfe 100644 --- a/src/server-actions/Recommendations/Recommendations.ts +++ b/src/server-actions/Recommendations/Recommendations.ts @@ -5,9 +5,9 @@ import { CreateServerAction } from ".." export const GetUserRecommendationsAction = CreateServerAction( true, - async (externalAuthId: string) => { + async (userId: string) => { try { - return await GetRecommendations(externalAuthId) + return await GetRecommendations(userId) } catch (error) { console.error("Error fetching recommendations:", error) throw error