отправка сообщений с картинками

This commit is contained in:
uniknow 2024-05-23 10:54:26 +04:00
parent 36f113187a
commit 44c149c60f
7 changed files with 348 additions and 123 deletions

View file

@ -1,9 +0,0 @@
@font-face {
font-family: 'Comfortaa';
src: url('./fonts/Comfortaa-VariableFont_wght.ttf') format('truetype');
font-weight: 1 1000; /* Объявляем диапазон веса шрифта */
font-style: normal;
font-stretch: normal;
}

View file

@ -14,6 +14,14 @@
<style lang="scss">
@font-face {
font-family: 'Comfortaa';
src: url('./fonts/Comfortaa-VariableFont_wght.ttf') format('truetype');
font-weight: 1 1000; /* Объявляем диапазон веса шрифта */
font-style: normal;
font-stretch: normal;
}
:root{
--bg: #101010;
--gradient: linear-gradient(to bottom, #3C53FF, #7734AA);
@ -34,7 +42,7 @@
background-color: var(--bg);
}
* {
*{
font-family: Comfortaa;
margin: 0;
}
@ -98,8 +106,11 @@
font-size: 20px;
font-weight: 100;
}
textarea{
font-size: 20px;
}
.noise {
.noiseGif {
position: relative;
width: 100%;
height: 100%;
@ -108,7 +119,7 @@
border-radius: 15px;
}
.noise::before {
.noiseGif::before {
content: '';
background-image: url(../noise.gif);
opacity: 0.011;
@ -122,5 +133,28 @@
border-radius: 15px;
}
.noisePic {
position: relative;
width: 100%;
height: 100%;
display: flex;
box-shadow: 4px 4px 11px rgba(#000000, 0.4);
border-radius: 15px;
}
.noisePic::before {
content: '';
background-image: url(../noise.png);
opacity: 0.811;
width: 100%;
height: 100%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
pointer-events: none;
border-radius: 15px;
}
</style>
</html>

View file

@ -6,11 +6,6 @@
credentials:'include'
})
if(!response.ok)
{
console.log(response.status)
}
if(response.ok)
{
let msgMassive = await response.json();
@ -19,18 +14,29 @@
localTime = new Date(msgMassive[i].created_at)
msgMassive[i].created_at = localTime
if(msgMassive[i].answer_id != null){
if(msgMassive[i].answer_id != null){
let answer = await getMessageById(chatId,msgMassive[i].answer_id)
msgMassive[i].answerMessage = answer.message
console.log(answer.message)
//console.log(answer.message)
}
}
msgMassive.reverse();
return msgMassive
}
else if(response.status === 404){
let msg = [];
return msg
}
else if(!response.ok)
console.log(response.status)
}
export async function getMessageById(chatId,msgId){
@ -44,7 +50,7 @@
return data;
}
else{
console.log(response.status)
return { message: "Сообщение не найдено" };
}
}
@ -102,4 +108,33 @@
else{
console.log(response.status)
}
}
}
export async function pinMessage(chatId,messageId){
const response = await fetch(`http://localhost:8000/api/chat/pinn_message?chat_id=${chatId}&message_id=${messageId}`,{
method:"POST",
credentials:'include'
})
if(response.ok){
return await response.json();
}
else
console.log(response.status)
}
export async function unpinMessage(chatId, messageId){
const response = await fetch(`http://localhost:8000/api/chat/unpinn_message?chat_id=${chatId}&message_id=${messageId}`,{
method:"DELETE",
credentials:'include'
})
if(response.ok){
return await response.json();
}
else
console.log(response.status)
}

View file

@ -16,7 +16,7 @@ export async function handleLogin(username, password) {
if(response.status === 200)
{
window.location.href = '/chatPage'
window.location.href = '/chat'
return ""
}
else if(response.status === 401)

View file

@ -17,9 +17,8 @@
let isOpen = false;
function dropDown() {
isOpen = !isOpen;
isOpen = !isOpen;
}
</script>
<header>
@ -29,28 +28,29 @@
</div>
<div class="userUser">
<button class="buttonUser"
style:border-bottom-right-radius={isOpen ? '0px' : '15px'}
style:border-bottom-left-radius= {isOpen ? '0px' : '15px'}
on:click={dropDown}>
<h3>{Nickname}</h3>
<div><img class="userAvatar" src={userImage} alt="аватарка"/></div>
</button>
{#if isOpen}
<div class="dropdown">
<button class="listItem" >Профиль</button>
<button class="listItem">Настройки</button>
<button on:click={handleLogout} class="listItem">Выйти</button>
</div>
{/if}
<button
class="buttonUser"
style:border-bottom-right-radius={isOpen ? '0px' : '15px'}
style:border-bottom-left-radius={isOpen ? '0px' : '15px'}
on:click={dropDown}
>
<h3>{Nickname}</h3>
<div><img class="userAvatar" src={userImage} alt="аватарка" /></div>
</button>
{#if isOpen}
<div class="dropdown">
<button class="listItem">Профиль</button>
<button class="listItem">Настройки</button>
<button on:click={handleLogout} class="listItem">Выйти</button>
</div>
{/if}
</div>
</header>
<style lang="scss">
.buttonUser,
.dropdown{
.dropdown {
border: 1px solid transparent;
background:
linear-gradient(#101010, #101010) padding-box,
@ -96,7 +96,7 @@
}
.dropdown {
width: 230px;
width: 228px;
display: flex;
flex-direction: column;
align-items: flex-start;
@ -111,17 +111,14 @@
border-radius: 50%;
}
.dropdown > *{
.dropdown > * {
cursor: pointer;
}
.listItem{
.listItem {
font-size: 16px;
}
.avatarDiv {
width: 230px;
height: 100%;

View file

@ -1,5 +1,5 @@
<script>
import { getLastMessages, MessagePicToUrl, getAllChats, getPinnedMsg, getMessageById } from '$lib/chat';
import { getLastMessages, MessagePicToUrl, getAllChats, getPinnedMsg, getMessageById, pinMessage, unpinMessage } from '$lib/chat';
import { UserCheck } from '$lib/userFunction'
import Header from '../Header.svelte';
import createWebSocket from '$lib/websocket';
@ -8,6 +8,8 @@
import { dayjs } from 'svelte-time';
import 'dayjs/locale/ru';
import { fade } from 'svelte/transition';
import {page} from '$app/stores';
import { writable } from 'svelte/store';
dayjs.locale('ru');
console.clear();
@ -18,70 +20,81 @@
let messages = [] //массив сообщений, которые отображаются на сайте
let msgLoaded = 0
let messageText = '' //сообщения для отправки
let selectedFile // картинка для отправки
let image_url = null
let messagePic //картинка для отправки
let flag = "send"
let answer = null
let chats = [] //массив чатов, доступных юзеру
let pinnedMsg = []
let chatId = null
onMount(async () => {
const userData = await UserCheck();
let userId = userData.id;
let chatId = 1;
userId = userData.id;
if(userId === undefined)
window.location.href = '/login'
const websocketUrl = `ws://localhost:8000/api/chat/ws/${chatId}?user_id=${userId}`;
chats = await getAllChats()
console.log(chats)
pinnedMsg = await getPinnedMsg(chatId)
async function handleChatUrlChange() {
// Проверяем, что текущий хэш соответствует шаблону для чата
if (window.location.hash.startsWith('#id=')) {
chatId = window.location.hash.slice(4);
console.log(chatId, " chatId")
chats = await getAllChats()
messages = await getLastMessages(chatId,msgLoaded);
console.log(messages)
const websocketUrl = `ws://localhost:8000/api/chat/ws/${chatId}?user_id=${userId}`
console.log(messages)
messages = await getLastMessages(chatId,msgLoaded)
pinnedMsg = await getPinnedMsg(chatId)
socket = createWebSocket(websocketUrl, async (message) => {
console.log(pinnedMsg, " pinned")
console.log(messages, " сообщения")
socket = createWebSocket(websocketUrl, async (message) => {
if(message.answer_id != null){
let answer = await getMessageById(chatId,message.answer_id)
message.answerMessage = answer.message
//console.log(answer.message)
}
let answer = await getMessageById(chatId,message.answer_id)
message.answerMessage = answer.message
console.log(answer.message)
if(message.flag === "delete"){
let messageToDelete = messages.findIndex(msg => msg.id === message.id)
console.log(messageToDelete, "индекс сообщения, которое нужно делитнуть")
messages.splice(messageToDelete,1)
messages = messages
console.log(messages," сообщения после удаления")
}
else{
messages = [...messages, message]
}
console.log(message, "пришло сообщение")
})
}
messages = [...messages, message];
});
}
handleChatUrlChange();
window.addEventListener('hashchange', handleChatUrlChange);
});
async function uploadImages() {
const fileInput = document.getElementById('file');
if(fileInput === null){
return null;
}
else{
const file = fileInput.files[0];
let urlpic;
if (file) {
urlpic = await MessagePicToUrl(file);
} else {
urlpic = null;
}
fileInput.value = null;
return urlpic;
}
}
async function sendMessage() {
if(messageText != ""){
socket.send(JSON.stringify({flag: flag,
message: messageText,
image_url: image_url,
answer: answer }));
messageText = ""
imageFile = undefined
imageShow = false
image_url = null
answer = null
}
}
function onEnterPress(event) {
@ -150,14 +163,67 @@ function helperDivShow(event, id) {
answer = pickedId
}
function pinFunc(event){
async function pinFunc(event){
let findPinMsg
if(pinnedMsg != null){
findPinMsg = pinnedMsg.find(msg => msg.id === pickedId)
console.log(findPinMsg)
}
if(findPinMsg != undefined){
console.log("удаляю сообщение")
unpinMessage(chatId,pickedId)
pinnedMsg = await getPinnedMsg(chatId)
console.log(pinnedMsg)
} else {
console.log("добавляю сообщение, потому что такого еще не было")
await pinMessage(chatId,pickedId)
pinnedMsg = await getPinnedMsg(chatId)
}} else {
console.log("добавляю сообщение, потому что сообщений нет")
await pinMessage(chatId,pickedId)
pinnedMsg = await getPinnedMsg(chatId)
console.log(pinmsg, " сообщения для закрепа", pinnedMsg, "массив закреп сообщений")
}}
function delFunc(event){
socket.send(JSON.stringify({"flag": "delete",
"user_id": userId,
"id": pickedId
}));
}
let imageFile = undefined
let imageShow = false;
$: console.log(imageFile, "картинка")
function triggerFileInput() {
imageFile.click();
}
function handleFileChange(event) {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
imageFile = e.target.result;
imageShow = true;
image_url = imageFile
};
reader.readAsDataURL(file);
}
}
function deleteImage(){
imageFile = undefined;
imageShow = false;
image_url = null
}
</script>
<svelte:window on:click={hideHelperDiv} />
@ -173,8 +239,10 @@ function helperDivShow(event, id) {
<div class="chatsDiv">
{#each chats as chat}
<div class="chatDivLeft">
<a class="aChatDivLeft" href={`/chat#id=${chat.chat_id}`}>
<img class="chatImage" src="{chat.avatar_image}" alt="аватарка">
<h2>{chat.chat_name}</h2>
</a>
</div>
{/each}
</div>
@ -183,15 +251,16 @@ function helperDivShow(event, id) {
<div>
<div class="gradient">
<div class="chatDiv">
{#if (messages.length === 0)}
<div class="noMsgDiv">
<h2 class="noMsg1">В этом чате еще нет сообщений.</h2>
<h3 class="noMsg2">Крыски, начните обсуждать <br> прям за ее спиной</h3>
</div>
{#if ((chatId != null) && (messages.length === 0))}
<div class="noMsgDiv">
<h2 class="noMsg1">В этом чате еще нет сообщений.</h2>
<h3 class="noMsg2">Крыски, начните обсуждать <br> прям за ее спиной</h3>
</div>
{/if}
<div class="msgDiv">
{#each messages as message}
<div class="messageMain">
@ -211,7 +280,7 @@ function helperDivShow(event, id) {
<div class="messageMessage">
<p>{message.message}</p>
{#if message.image_url != null}
<img src="{message.image_url}" alt="пикча">
<img src="{message.image_url}" alt="пикча" class="messageImage">
{/if}
</div>
@ -219,26 +288,41 @@ function helperDivShow(event, id) {
</div>
{/each}
</div>
<!-- {#if showDiv} -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div id="helperDiv" class="helperDiv" on:contextmenu={(event) => event.preventDefault()}>
<button on:click={ansFunc} class="helpDiv"><img class="helpImg" src="./icon/answer.png" alt="ans"><p class="ans">Ответить</p></button>
<button on:click={pinFunc} class="helpDiv"><img class="helpImg" src="./icon/pin.png" alt="pin"><p class="pin">Закрепить</p></button>
<button on:click={delFunc} class="helpDiv"><img class="helpImg" src="./icon/trash.png" alt="del"><p class="del">Удалить</p></button>
</div>
<!-- {/if} -->
{#if (chatId != null)}
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<div class="inputDiv">
<!-- svelte-ignore a11y-autofocus -->
<textarea on:keydown={onEnterPress}
autofocus placeholder="Введите сообщение" rows="{rows}" bind:value={messageText}
on:input={onInput} name="msg" id="msg"></textarea>
{#if imageShow == true}
<div class="imageDiv">
<img src="{imageFile}" alt="" class="imageFile">
<button on:click={deleteImage} class="imageDelete">x</button>
</div>
{/if}
<img class="logoForImage" src="logoForImage.svg" alt="">
<!-- svelte-ignore a11y-autofocus -->
<div class="textMsg">
<textarea on:keydown={onEnterPress}
autofocus placeholder="Введите сообщение" rows="{rows}" bind:value={messageText}
on:input={onInput} name="msg" id="msg"></textarea>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<img class="logoForImage" src="logoForImage.svg" alt=""
on:click={() => document.getElementById('fileInput').click()}>
</div>
<input type="file" accept=".png, .jpeg, .jpg, .gif" id="fileInput"
bind:this={imageFile} on:change={handleFileChange} style="display: none;">
</div>
{/if}
</div>
</div>
@ -250,12 +334,15 @@ function helperDivShow(event, id) {
<h3 class="noMsg2">Но если ты закрепишь сообщение, <br> тут что то изменится</h3>
</div>
{:else}
{#each pinnedMsg as msg}
<div class="mainPinned">
<h3 class="msgPinned">{msg.message}</h3>
<img class="imgPinned" src="{msg.avatar_image}" alt="">
<div class="pinnedMain">
{#each pinnedMsg as msg}
<div class="pinDiv">
<div class="pinImg"><img class="pinnedImg" src="{msg.avatar_image}" alt=""></div>
<div class="pinMsg"><h3 class="pinnedMsg">{msg.message}</h3></div>
</div>
{/each}
</div>
{/each}
{/if}
</div></div>
@ -269,6 +356,76 @@ function helperDivShow(event, id) {
<style lang="scss">
::-webkit-scrollbar-thumb:hover {
background: white; /* Цвет ползунка при наведении */
}
::-webkit-scrollbar-track {
background: #f1f1f1; /* Цвет трека */
border-radius: 6px; /* Радиус скругления */
}
::-webkit-scrollbar-thumb {
background-color: transparent; /* Цвет ползунка */
border-radius: 6px; /* Радиус скругления */
border: 3px solid #ffffff00; /* Цвет фона внутри ползунка */
}
.imageDiv{
position: relative;
padding-top: 5px;
}
.imageDelete{
position: absolute;
cursor: pointer;
}
.textMsg{
display: flex;
flex-direction: row;
}
.imageFile{
border-radius: 15px;
height: auto;
width: 250px;
}
.pinMsg{
width: 90%;
}
.pinImg{
width: 10%;
margin-right: 15px;
}
.pinnedImg{
width: 60px;
height: auto;
border-radius: 15px;
}
.pinnedMsg{
display: flex;
width: 90%;
}
.pinDiv{
display: flex;
width: 100%;
}
.pinnedMain{
display: flex;
flex-direction: column;
margin: 10px;
width: 100%;
height: 100%;
margin-bottom: 10px;
}
.nameAnswerDiv > p,img{
margin-left: 5px;
}
@ -296,6 +453,7 @@ function helperDivShow(event, id) {
display: flex;
flex-direction: row;
cursor: pointer;
}
.helpImg{
@ -303,6 +461,7 @@ function helperDivShow(event, id) {
width: 25px;
height: 25px;
margin-right: 5px;
margin-left: -5px;
}
.helperDiv{
@ -313,9 +472,8 @@ function helperDivShow(event, id) {
transition: opacity 0.3s;
opacity: 0;
border-bottom-left-radius: 15px;
border-bottom-left-radius: 15px;
border-bottom-right-radius: 15px;
border-bottom: 0;
border-top-right-radius: 15px;
border-top-left-radius: 0;
@ -326,12 +484,6 @@ function helperDivShow(event, id) {
}
.imgPinned{
height: 60px;
width: 60px;
border-radius: 15px;
}
.nameAnswerDiv{
display: flex;
flex-direction: row;
@ -346,21 +498,32 @@ function helperDivShow(event, id) {
height: 100%;
overflow: hidden;
}
.aChatDivLeft{
display: flex;
flex-direction: row;
align-items: center;
/* Задаем блочный тип элемента */
width: 100%;
text-decoration: none;
}
.chatDivLeft{
display: flex;
flex-direction: row;
align-items: center;
width: 95%;
height: 75px;
margin-top: 10px;
border-radius: 15px;
border: 1px solid transparent;
background:
linear-gradient(#101010, #101010) padding-box,
var(--gradient) border-box;
}
.chatImage{
height: 60px;
width: 60px;
@ -378,6 +541,11 @@ function helperDivShow(event, id) {
//background-color: red;
}
.messageImage{
margin-top: 5pxS;
border-radius: 15px;
}
.messageMessage{
background-color: #7734AA;
border-radius: 15px;
@ -406,11 +574,12 @@ padding-bottom: 10px;
margin-bottom: 10px;
overflow: auto;
//background-color: red;
scroll-behavior: smooth;
}
.inputDiv{
display: flex;
flex-direction: row;
flex-direction: column;
border-radius: 15px;
border: 1px solid transparent;
background:

View file

@ -50,7 +50,6 @@
let greeting = ' ';
let greetings = [
'Опять ты? Ну давай, заходи',
'Рад видеть тебя снова',
'Как прошел день?',
'Как настроение?',
@ -73,7 +72,7 @@
<div class="loginField">
<div class="loginMainDiv">
<div class="loginDiv" transition:fly={{ y: -1920, duration: 1000, backInOut }}>
<div class="noise">
<div class="noiseGif">
<div class="marginDiv">
<div class="greetingsDiv">
@ -92,7 +91,7 @@
<div class="group">
<h3>пароль</h3>
<input placeholder=" " type="password" id="password" on:input={listener} bind:value={password} />z
<input placeholder=" " type="password" id="password" on:input={listener} bind:value={password} />
</div>
</div>
@ -108,7 +107,7 @@
</div>
</div>
<div class="regDiv" transition:fly={{ y: -1920, duration: 800, backInOut }}>
<div class="noise">
<div class="noiseGif">
<div class="regregDiv">
<h2 class="reg1">Нет аккаунта? Лох!</h2>
<button class="reg2" on:click={() => (window.location.href = '/register')}