Skip to content

Commit

Permalink
added delete confirmation by code
Browse files Browse the repository at this point in the history
  • Loading branch information
Andcool-Systems committed Dec 29, 2024
1 parent 7c8dab0 commit e476b1d
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 82 deletions.
2 changes: 1 addition & 1 deletion src/app/me/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ const Login = () => {
<img alt="" src="/static/icons/discord.svg" />
Discord
</a>
<MinecraftConnect onInput={loginMinecraft}>
<MinecraftConnect onInput={loginMinecraft} login>
<div
className={styles.login_button}
style={{ '--color': '#56ff4b' } as CSSProperties}
Expand Down
72 changes: 24 additions & 48 deletions src/app/me/settings/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,16 @@ import {
IconShield,
IconDeviceMobile,
IconDeviceDesktop,
IconBrandMinecraft
IconBrandMinecraft,
IconPlugConnected
} from '@tabler/icons-react';
import { timeStamp } from '@/app/modules/utils/time';
import style_workshop from "@/app/styles/workshop/page.module.css";
import SlideButton from '@/app/modules/components/SlideButton';
import ApiManager from '@/app/modules/utils/apiManager';
import { Session } from '@/app/interfaces';
import { setTheme } from './setTheme';
import MinecraftConnect from '@/app/modules/components/MinecraftConnect';
const fira = Fira_Code({ subsets: ["latin"] });

export interface SettingsResponse {
Expand Down Expand Up @@ -88,7 +90,7 @@ const Page = () => {
<div
id="sidebar"
className={Style.main}
style={loaded ? { opacity: "1", transform: "translateY(0)" } : { opacity: "0", transform: "translateY(50px)" }}
style={loaded ? { opacity: "1", transform: "none" } : { opacity: "0", transform: "translateY(50px)" }}
>
{data &&
<>
Expand All @@ -106,31 +108,23 @@ const Page = () => {
}

const UserSettings = ({ data }: { data: SettingsResponse }) => {
const changePublic = (state: boolean): Promise<void> => {
return new Promise((resolve, reject) => {
ApiManager.setPublicProfile({ state })
.then(() => resolve())
.catch(reject);
});
}

return (
<div className={Style.container}>
<h3><IconUser width={26} height={26} />Настройки аккаунта</h3>
<SlideButton
label='Публичный профиль'
defaultValue={data.can_be_public ? data?.public_profile : false}
loadable={true}
strict={true}
onChange={changePublic}
defaultValue={data.can_be_public ? data.public_profile : false}
onChange={state => ApiManager.setPublicProfile({ state })}
disabled={!data.can_be_public}
loadable
strict
/>
</div>
);
}

const Connections = ({ data, refetch }: { data: SettingsResponse, refetch(): void }) => {
const refresh = () => {
const refreshMinecraft = () => {
const load_icon = document.getElementById('refresh');
load_icon.style.animation = `${Style.loading} infinite 1s reverse ease-in-out`;

Expand Down Expand Up @@ -163,18 +157,14 @@ const Connections = ({ data, refetch }: { data: SettingsResponse, refetch(): voi
})
}

const connectMinecraft = () => {
const target = document.getElementById('code') as HTMLInputElement;
if (target.value.length != 6) return;

ApiManager.connectMinecraft(target.value)
.then(refetch)
.catch(response => {
const data = response.data as { message: string };
const err = document.getElementById('error') as HTMLParagraphElement;
err.innerText = data.message;
});
}
const connectMinecraft = async (code: string): Promise<void> => {
try {
await ApiManager.connectMinecraft(code);
setTimeout(refetch, 150);
} catch (error) {
throw error;
}
};

return (
<>
Expand Down Expand Up @@ -224,7 +214,7 @@ const Connections = ({ data, refetch }: { data: SettingsResponse, refetch(): voi
</div>
<div className={Style.checkboxes}>
<span>Последний раз кэшировано {formatDate(new Date(data.connections?.minecraft?.last_cached))}</span>
<button className={Style.unlink} onClick={refresh}>
<button className={Style.unlink} onClick={refreshMinecraft}>
<IconRefresh style={{ width: "1.8rem" }} id="refresh" />Обновить кэш
</button>

Expand All @@ -233,26 +223,12 @@ const Connections = ({ data, refetch }: { data: SettingsResponse, refetch(): voi
</button>
</div>
</> : <>
<p style={{ margin: 0 }}>Привяжите свою учётную запись Minecraft к учетной записи PPLBandage для управления кэшем скинов и настройками видимости
вашего никнейма в поиске.</p>
<p style={{ marginBottom: 0, marginTop: '.5rem' }}>
Зайдите на Minecraft сервер&nbsp;
<span
style={{ textDecoration: "underline", cursor: "pointer", fontWeight: "600" }}
onClick={() => { navigator.clipboard?.writeText("oauth.pplbandage.ru"); }}>
oauth.pplbandage.ru
</span>&nbsp;(версия 1.8-текущая) и получите там 6-значный код.</p>

<div>
<div className={Style.code_container}>
<input placeholder="Введите 6-значный код" type='number' id='code' className={Style.code_input} onChange={e => {
const target = document.getElementById('code') as HTMLInputElement;
if (target.value.length > 6) target.value = target.value.slice(0, 6)
}} />
<button className={Style.code_send} onClick={connectMinecraft}>Отправить</button>
</div>
<p style={{ margin: 0, color: "#dd0f0f", marginTop: "5px" }} id="error"></p>
</div>
<p style={{ margin: 0 }} >Подключите свой аккаунт Minecraft, чтобы управлять кэшем скинов и настройками видимости вашего никнейма в поиске.</p>
<MinecraftConnect onInput={connectMinecraft}>
<button className={Style.unlink} style={{ width: '100%' }}>
<IconPlugConnected style={{ width: "1.8rem" }} />Подключить
</button>
</MinecraftConnect>
</>}
</div>
</>
Expand Down
101 changes: 101 additions & 0 deletions src/app/modules/components/EditConfirmation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { useState } from "react";
import { CSSTransition } from "react-transition-group"
import style_base from '@/app/styles/minecraftConnect.module.css';
import style from '@/app/styles/EditConfirmation.module.css';
import { IconArchive, IconTrash, IconX } from "@tabler/icons-react";

interface EditConfirmationProps {
children: JSX.Element,
onInput(): Promise<void>,
confirm_code: string,
action: 'delete' | 'archive'
}

const EditConfirmation = ({ action, confirm_code, children, onInput }: EditConfirmationProps) => {
const [expanded, setExpanded] = useState<boolean>(false);
const [available, setAvailable] = useState<boolean>(false);

const titles = {
delete: 'Подтвердите удаление',
archive: 'Подтвердите архивацию'
}

const icons = {
delete: <IconTrash />,
archive: <IconArchive />
}

const action_confirm = {
delete: 'Удалить',
archive: 'Архивировать'
}

return (
<>
<div onClick={() => setExpanded(true)}>
{children}
</div>
<CSSTransition
in={expanded}
timeout={150}
classNames={{
enter: style_base['background-enter'],
enterActive: style_base['background-enter-active'],
exit: style_base['background-exit'],
exitActive: style_base['background-exit-active'],
}}
unmountOnExit>
<div className={style_base.background} />
</CSSTransition>

<CSSTransition
in={expanded}
timeout={150}
classNames={{
enter: style_base['menu-enter'],
enterActive: style_base['menu-enter-active'],
exit: style_base['menu-exit'],
exitActive: style_base['menu-exit-active'],
}}
unmountOnExit>
<div className={style_base.base}>
<div className={style_base.container}>
<div className={style_base.header}>
<h3 style={{ margin: 0, display: 'flex', gap: '.5rem', alignItems: 'center' }}>{icons[action]}{titles[action]}</h3>
<IconX className={style_base.close} onClick={() => setExpanded(false)} />
</div>
<p style={{ margin: 0, fontSize: '.9rem', fontWeight: 'bold' }}>Это действие имеет необратимый характер!</p>
<p style={{ margin: 0, userSelect: 'none', marginTop: '.5rem' }}>Для продолжения введите `<b>{confirm_code}</b>` ниже</p>

<input
style={{ borderRadius: '10px' }}
placeholder='Введите идентификатор повязки'
id='id'
className={style_base.code_input}
onChange={e => setAvailable(e.target.value === confirm_code)} />

<button
className={`${style.button} ${available && style.available}`}
disabled={!available}
onClick={() => {
if (!available) return;
onInput()
.then(() => setExpanded(false))
.catch(response => {
const err = document.getElementById('error') as HTMLParagraphElement;
err.innerText = response;
err.style.display = 'block';
})
}}>
{action_confirm[action]}
</button>

<p style={{ margin: 0, color: '#ED4245', display: 'none' }} id="error" />
</div>
</div>
</CSSTransition>
</>
);
}

export default EditConfirmation;
2 changes: 1 addition & 1 deletion src/app/modules/components/MeSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export const Me = ({ children, user_data }: { children: JSX.Element, user_data?:

return (
<div className={style_sidebar.main_container}>
<div style={islogged ? { opacity: "1", transform: "translateY(0)" } : {}} className={style_sidebar.hidable}>
<div style={islogged ? { opacity: "1", transform: "none" } : {}} className={style_sidebar.hidable}>
<div className={style_sidebar.main}>
<div className={style_sidebar.side}>
{!!data &&
Expand Down
13 changes: 8 additions & 5 deletions src/app/modules/components/MinecraftConnect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import { useState } from "react";
import { CSSTransition } from "react-transition-group"
import style from '@/app/styles/minecraftConnect.module.css';
import { IconBrandMinecraft, IconCheck, IconX } from "@tabler/icons-react";
import ApiManager from "../utils/apiManager";

interface MinecraftConnectProps {
children: JSX.Element,
onInput(code: string): Promise<void>
onInput(code: string): Promise<void>,
login?: boolean
}

const MinecraftConnect = ({ children, onInput }: MinecraftConnectProps) => {
const MinecraftConnect = ({ login, children, onInput }: MinecraftConnectProps) => {
const [expanded, setExpanded] = useState<boolean>(false);

const selectText = (nodeId: string) => {
Expand All @@ -23,6 +23,8 @@ const MinecraftConnect = ({ children, onInput }: MinecraftConnectProps) => {
}
}

const title = login ? 'Войти через Minecraft' : 'Подключить аккаунт Minecraft';

return (
<>
<div onClick={() => setExpanded(true)}>
Expand Down Expand Up @@ -54,10 +56,10 @@ const MinecraftConnect = ({ children, onInput }: MinecraftConnectProps) => {
<div className={style.base}>
<div className={style.container}>
<div className={style.header}>
<h3 style={{ margin: 0, display: 'flex', gap: '.5rem', alignItems: 'center' }}><IconBrandMinecraft />Войти через Minecraft</h3>
<h3 style={{ margin: 0, display: 'flex', gap: '.5rem', alignItems: 'center' }}><IconBrandMinecraft />{title}</h3>
<IconX className={style.close} onClick={() => setExpanded(false)} />
</div>
<p style={{ margin: 0, fontSize: '.9rem', opacity: .6 }}>Этот способ будет работать, если вы привязали аккаунт Minecraft в личном кабинете.</p>
{login && <p style={{ margin: 0, fontSize: '.9rem', opacity: .6 }}>Этот способ будет работать, если вы привязали аккаунт Minecraft в личном кабинете.</p>}
<p style={{ margin: 0, fontSize: '.95rem' }}>Зайдите на Minecraft сервер
`<span style={{ color: "rgba(12, 247, 215)" }} id="oauth_name" onClick={() => selectText('oauth_name')}>
oauth.pplbandage.ru
Expand All @@ -80,6 +82,7 @@ const MinecraftConnect = ({ children, onInput }: MinecraftConnectProps) => {
if (target.value.length != 6) return;

onInput(target.value)
.then(() => setExpanded(false))
.catch(response => {
const data = response.data as { message: string };
const err = document.getElementById('error') as HTMLParagraphElement;
Expand Down
6 changes: 3 additions & 3 deletions src/app/modules/utils/apiManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,12 @@ class ApiManager {
}

/* Set public profile */
static async setPublicProfile(params: { state: boolean }): Promise<boolean> {
return (await this.doRequest({
static async setPublicProfile(params: { state: boolean }): Promise<void> {
await this.doRequest({
url: `/user/me`,
method: 'PATCH',
data: { public: params.state }
})).data.new_data;
});
}

/* Set user profile theme */
Expand Down
25 changes: 25 additions & 0 deletions src/app/styles/EditConfirmation.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
.button {
color: var(--main-text-color);
background-color: var(--main-card-color);
border-radius: 10px;
border: 1px var(--main-element-color) solid;
height: 2.4rem;
box-sizing: border-box;
cursor: auto;
transition: background-color 250ms, border 150ms;
font-weight: 600;
font-family: inherit;
font-size: 1rem;
display: flex;
align-items: center;
flex-direction: row;
justify-content: center;
}

.available {
cursor: pointer;
}

.available:hover {
background-color: #ED4245;
}
6 changes: 2 additions & 4 deletions src/app/styles/me/me.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,8 @@

.login_main {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
inset: 0;
z-index: 2;

display: flex;
align-items: center;
Expand Down
2 changes: 1 addition & 1 deletion src/app/styles/minecraftConnect.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
position: fixed;
inset: 0;
z-index: 9000;
background-color: rgba(0, 0, 0, 0.4);
background-color: rgba(0, 0, 0, 0.6);
}

.container {
Expand Down
2 changes: 1 addition & 1 deletion src/app/workshop/[id]/client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ export default function Home({ data, referrer }: { data: Interfaces.Bandage, ref

<main
className={style.main}
style={loaded ? { opacity: '1', transform: 'translateY(0)' } : { opacity: '0', transform: 'translateY(50px)' }}
style={loaded ? { opacity: '1', transform: 'none' } : { opacity: '0', transform: 'translateY(50px)' }}
>
<NavigatorEl path={navPath}
style={{ marginBottom: "1rem" }} />
Expand Down
Loading

0 comments on commit e476b1d

Please sign in to comment.