从零开始用react + tailwindcss + express + mongodb实现一个聊天程序(六) 导航栏 和 个人信息设置

1.导航栏(navbar)

 在components下面 创建NavBar.jsx

import { MessageSquare,Settings,User,LogOut} from "lucide-react"

import {Link} from "react-router-dom"

import { useAuthStore } from "../store/useAuthStore"

const NavBar = () => {

    const {authUser,logout} = useAuthStore()

  return (

    <header className="bg-base-100 border-b border-base-300 fixed w-full top-0 z-40

        backdrop-blur-lg bg-base-100/80">

        <div className="container mx-auto px-4 h-16">

            <div className="flex items-center justify-between h-full">

                <div className="flex items-center gap-8">

                    <Link to="/" className="flex items-center gap-2.5 hover:opacity-80 transition-all duration-200">

                        <div className="size-9 rounded-lg bg-primary/10 flex items-center justify-center">

                            <MessageSquare className="w-5 h-5 text-primary"/>

                        </div>

                        <h1 className="text-lg font-bold">HamburgerChat</h1>

                    </Link>

                </div>

                <div className="flex items-center gap-2">

                    <Link to="/settings" className={`btn btn-sm gap-2 transition-colors`}>

                        <Settings className="size-5"></Settings>

                        <span className="hidden sm:inline">设置</span>

                    </Link>

                        // 只有登录了 才会显示 个人资料和退出按钮

                    {authUser && (

                        <>

                            <Link to="/profile" className={`btn btn-sm gap-2 transition-colors`}>

                                <User className="size-5"></User>

                                <span className="hidden sm:inline">个人资料</span>

                            </Link>

                            <button className="flex items-center gap-2" onClick={logout}>

                                <LogOut className="size-5"></LogOut>

                                <span className="hidden sm:inline">退出</span>

                            </button>

                        </>

                    )}

                </div>

               

            </div>

        </div>

    </header>

  )

}

export default NavBar

 然后再App.jsx引入 NavBar.jsx组件

import NavBar from '@/components/NavBar' 

并使用组件 加在Routes配置上面

         <NavBar />

      <Routes>

        <Route path="/" element={authUser?<HomePage />: <Navigate to="/login" />} />

        <Route path="/signup" element={!authUser ? <SignUpPage />:<Navigate to="/" />} />

        <Route path="/login" element={!authUser ?<LoginPage /> : <Navigate to="/" />} />

        <Route path="/settings" element={<SettingsPage /> } />

        <Route path="/profile" element={authUser ? <ProfilePage />:<Navigate to="/login" />} />

      </Routes>

效果如图

点击退出按钮 会跳转到 登录页面  导航栏这就完成了。

2.个人信息设置

 修改ProfilePage内容    Profile最主要的内容就是 点击头像 上的小相机图标 我们可以上传更换头像。上传功能我们是使用cloudinary (类似七牛云 阿里oss)。网址:https://cloudinary.com/

我们在官方申请账号

 1.后端接口

在server 下 .env配置

在lib下新建cloudinary.js  使用我们申请的key

import {v2 as cloudinary} from 'cloudinary'
import  {config} from "dotenv"config()cloudinary.config({cloud_name: process.env.CLOUDINARY_NAME,api_key: process.env.CLOUDINARY_API_KEY,api_secret: process.env.CLOUDINARY_API_SECRET
})export default cloudinary

接下来在后端实现 保存个人信息接口

在server auth.route.js 增加保存信息路由

先引入updateProfile方法

import {signUp, login,logout,checkAuth,updateProfile} from "../controllers/auth.controller.js"

router.put('/update-profile', protectRoute, updateProfile) 

在auth.controller.js 增加UpdateProfile方法

2.前端页面 

  在useAuthStore中增加  保存信息loading状态 和请求方法  

  isUpdatingProfile: false, // 是否更新中

updateProfile: async(data) => {

        set({isUpdatingProfile: true})

        try {

            const res = await axiosInstance.put('/auth/update-profile', data)

            set({authUser: res.data})   // 请求成功后 更新当前user的信息

            toast.success("资料更新成功")

        } catch (error) {

            console.log("useAuthStore updateProfile error",error.message)

            toast.error(error.response.data.message)

        } finally {

            set({isUpdatingProfile: false})

        }

    },

修改ProfilePage.jsx

import { useState } from "react";
import { useAuthStore } from "../store/useAuthStore";
import {Camera,User,Mail} from "lucide-react";
const ProfilePage = () => {const [selectedImage, setSelectedImage] = useState(null)const { authUser, isUpdatingProfile,updateProfile } = useAuthStore();const handlerImageUpload = async (e) => {const file = e.target.files[0];if (!file) return;const reader = new FileReader();reader.readAsDataURL(file);reader.onload = async () => {const base64Image = reader.result;await updateProfile({ profilePic: base64Image });}}return (<div className="h-screen pt-20"><div className="max-w-2xl mx-auto py-8"><div className="bg-base-300 rounded-xl p-6 space-y-8"><div className="text-center"><h1 className="text-2xl font-semibold">个人资料</h1><p className="mt-2">你的个人信息</p></div>{/* 头像 */}<div className="flex flex-col items-center gap-4"><div className="relative"><img src={selectedImage || authUser.profilePic || "https://placehold.co/128x128"} alt="profile"className="size-32 rounded-full object-cover border-4"></img><label htmlFor="avatar-upload"className={`absolute bottom-0 right-0 bg-base-content hover:scale-105p-2 rounded-full cursor-pointer transition-all duration-300${isUpdatingProfile ? 'animate-pulse pointer-events-none' : ''}`}><Camera className="size-5 text-base-200" /><inputtype="file"id="avatar-upload"className="hidden"accept="image/*"onChange={handlerImageUpload}disabled={isUpdatingProfile}/></label></div><p className="text-sm text-zinc-400">{isUpdatingProfile ? "上传中..." : "点击相机上传头像"}</p></div>{/* 用户信息 */}<div className="space-y-6"><div className="space-y-1.5"><div className="text-sm text-zinc-400 flex items-center gap-2"><User className="size-4"/>用户名</div><p className="px-4 py-2.5 bg-base-200 rounded-lg border">{authUser?.userName}</p></div><div className="space-y-1.5"><div className="text-sm text-zinc-400 flex items-center gap-2"><Mail className="size-4"/>邮箱地址</div><p className="px-4 py-2.5 bg-base-200 rounded-lg border">{authUser?.email}</p></div></div>{/* 账号状态 */}<div className="mt-6 bg-base-300 rounded-xl p-6"><h2 className="text-lg font-medium mb-4">账号信息</h2><div className="spacy-y-3 text-sm"><div className="flex items-center justify-between py-2border-b border-zinc-700"><span>账号注册时间</span><span>{authUser.createdAt?.split("T")[0]}</span></div><div className="flex items-center justify-between py-2border-b border-zinc-700"><span>账号状态</span><span className="text-green-500">正常</span></div></div></div></div></div></div>)
}export default ProfilePage

效果如图

点击头像小相机 选择一张小于50kb的图片上传更新 头像 

这就是今天内容 下篇实现主题设置  欢迎评论区留言 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/26210.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何通过 LlamaIndex 将数据导入 Elasticsearch

作者&#xff1a;来自 Elastic Andre Luiz 逐步介绍如何使用 RAG 和 LlamaIndex 提取数据并进行搜索。 在本文中&#xff0c;我们将使用 LlamaIndex 来索引数据&#xff0c;从而实现一个常见问题搜索引擎。 Elasticsearch 将作为我们的向量数据库&#xff0c;实现向量搜索&am…

yunedit-post ,api测试比postman更好

postman应该是大家最熟悉的api测试软件了&#xff0c;但是由于它是外国软件&#xff0c;使用它的高端功能注册和缴费都比较麻烦。生成在线文档分享也经常无法访问被拦截掉。 这里可以推荐一下yunedit-post&#xff0c;该有的功能都有。 https://www.yunedit.com/postdetail …

Gopeed 各种类型的文件资源下载器 v1.6.7 中文版

Gopeed 是一款由 Go 和 Flutter 开发的下载器。它具有简洁美观的界面以及强大的功能&#xff0c;支持 HTTP、BitTorrent、Magnet 等协议&#xff0c;并且可以在全平台上使用。 开发语言及技术&#xff1a;Gopeed 采用 Go 和 Flutter 进行开发。Go 语言具有高效、简洁的特点&am…

3d投影到2d python opencv

目录 cv2.projectPoints 投影 矩阵计算投影 cv2.projectPoints 投影 cv2.projectPoints() 是 OpenCV 中的一个函数&#xff0c;用于将三维空间中的点&#xff08;3D points&#xff09;投影到二维图像平面上。这在计算机视觉中经常用于相机标定、物体姿态估计、3D物体与2D图…

Linux操作系统5-进程信号3(信号产生总结与核心转储)

上篇文章&#xff1a;Linux操作系统5-进程信号2&#xff08;信号的4种产生方式&#xff0c;signal系统调用&#xff09;-CSDN博客 本篇Gitee仓库&#xff1a;myLerningCode/l25 橘子真甜/Linux操作系统与网络编程学习 - 码云 - 开源中国 (gitee.com) 本篇重点&#xff1a;核心…

Linux《基础开发工具(上)》

在之前的篇章当中我们已经了解了Linux当中基本的指令以及相关的知识&#xff0c;那么接下来在本篇当中就开始学基本的开发工具&#xff0c;在此我们一共要了解6大开发工具&#xff0c;在此将这些工具的学习分为上中下篇&#xff0c;在本篇当中我们首先要来学习的是yun以及vim,一…

kali liux的下载

Kali Linux | Penetration Testing and Ethical Hacking Linux Distributionhttps://www.kali.org/ VMware虚拟机https://pan.quark.cn/s/aa869ffbf184 【补充一个今天学到的知识昂和内容无关:&#xff08;遥感&#xff09;指非接触的远距离探测技术&#xff0c;使用传感器探…

微软AI900认证备考全攻略:开启AI职业进阶之路

在当今数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;正深刻地改变着我们的工作和生活。微软AI900认证作为AI领域的权威认证之一&#xff0c;不仅为技术爱好者提供了深入探索AI的机会&#xff0c;更是开启AI职业进阶之路的重要敲门砖。以下是一份全面的备考攻略&am…

【Mark】记录用宝塔+Nginx+worldpress+域名遇到的跨域,301,127.0.0.1,CSS加载失败问题

背景 想要用宝塔搭建worldpress&#xff0c;然后用域名直接转https&#xff0c;隐藏掉ipport。 结果被折磨了1天&#xff0c;一直在死活在301&#xff0c;127.0.0.1打转 还有css加载不了的情况 因为worldpress很多是301重定向的&#xff0c;所以改到最后我都不知道改了什么&am…

算法题001——移动零

移动零 力扣——移动零点击链接即可跳转 这道题的数组被划分为两个区间&#xff0c;前一个区间为 非零元素&#xff0c;而后一个指针是 零元素 我们运用双指针&#xff0c;先定义两个指针&#xff0c;分别为 dest 和 cur , cur用来遍历整个数组&#xff0c;而 dest 表示我们…

Selenium自动化测试:如何搭建自动化测试环境,搭建环境过程应该注意的问题

最近也有很多人私下问我&#xff0c;selenium学习难吗&#xff0c;基础入门的学习内容很多是3以前的版本资料&#xff0c;对于有基础的人来说&#xff0c;3到4的差别虽然有&#xff0c;但是不足以影响自己&#xff0c;但是对于没有学过的人来说&#xff0c;通过资料再到自己写的…

mysql 全方位安装教程

下载 MySQL 【官网下载地址】 注意要选择较大的哪个安装包&#xff0c;小的安装包是一个安装器。 我们不用登录&#xff0c;直接下载 直接运行下载好的安装包 MySQL如果是 安装包安装, 可以图形化界面自主配置 如果是压缩包解压, 可以配置 配置文件, 可以解压安装到指定的…

深入刨析 之C++ string类

欢迎来到干货小仓库&#xff01;&#xff01;&#xff01; 没有完美的计划&#xff0c;每个人都在试验的过程中渐渐清晰!!! 1.标准库的string类 a. string是表示字符串的字符串类。 b. 该类的接口与常规容器的接口基本相同&#xff0c;再添加了一些专门用来操作string的常规操…

【AI论文】MedVLM-R1:通过强化学习激励视觉语言模型(VLMs)的医疗推理能力

摘要&#xff1a;推理是推进医学影像分析的关键前沿领域&#xff0c;其中透明度和可信度对于赢得临床医生信任和获得监管批准起着核心作用。尽管医学视觉语言模型&#xff08;VLMs&#xff09;在放射学任务中展现出巨大潜力&#xff0c;但大多数现有VLM仅给出最终答案&#xff…

深入理解并实现自定义 unordered_map 和 unordered_set

亲爱的读者朋友们&#x1f603;&#xff0c;此文开启知识盛宴与思想碰撞&#x1f389;。 快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 在 C 的标准模板库&#xff08;STL&#xff09;中&#xff0c;unorder…

使用ChatGPT-Deep Reaserch两步给出文献综述!

文献综述是学术论文写作中不可或缺的一部分&#xff0c;它不仅是对已有研究的梳理和总结&#xff0c;更是为后续研究奠定理论基础的关键步骤。通过文献综述研究者能够全面了解当前研究领域的现状、主要观点和研究方法&#xff0c;从而找到自己研究的切入点和创新点。这一过程需…

[Java基础] JVM常量池介绍(BeanUtils.copyProperties(source, target)中的属性值引用的是同一个对象吗)

文章目录 1. JVM内存模型2. 常量池中有什么类型&#xff1f;3. 常量池中真正存储的内容是什么4. 判断一个字符串(引用)是否在常量池中5. BeanUtils.copyProperties(source, target)中的属性值引用的是同一个对象吗&#xff1f;6. 获取堆内存使用情况、非堆内存使用情况 1. JVM内…

塔能科技:工厂智慧照明,从底层科技实现照明系统的智能化控制

在全球节能减碳和智慧生活需求激增的背景下&#xff0c;基于“用软件定义硬件&#xff0c;让物联运维更简捷更节能”的产品理念&#xff0c;塔能科技的智慧照明一体化方案如新星般崛起&#xff0c;引领照明行业新方向。现在&#xff0c;我们来深入探究其背后的创新技术。该方案…

RabbitMq-消息确认机制-消息队列可靠投递

RabbitMq-消息确认机制-消息队列可靠投递 发送端确认 ConfirmCallback 在spring中开启ConfirmCallback&#xff0c; springboot rabbitmq属性配置spring.rabbitmq.publisher-confirm和spring.rabbitmq.publisher-confirm-type详解_弃用的配置属性 spring.rabbitmq.publisher-…

水滴tabbar canvas实现思路

废话不多说之间看效果图,只要解决了这个效果水滴tabbar就能做出来了 源码地址 一、核心实现步骤分解 布局结构搭建 使用 作为绘制容器 设置 width=600, height=200 基础尺寸 通过 JS 动态计算实际尺寸(适配高清屏) function initCanvas() {// 获取设备像素比(解决 Re…