This commit is contained in:
2025-04-03 17:58:09 +05:00
parent f1b6035192
commit b44c52eed6
17 changed files with 91 additions and 53 deletions
+29 -8
View File
@@ -1,6 +1,6 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { useMask } from "@react-input/mask"; import { useMask } from "@react-input/mask";
import { useState } from "react";
interface InputProps { interface InputProps {
type?: "text" | "email" | "password" | "time" | "tel" | "number"; type?: "text" | "email" | "password" | "time" | "tel" | "number";
value?: string; value?: string;
@@ -10,8 +10,10 @@ interface InputProps {
readOnly?: boolean; readOnly?: boolean;
className?: string; className?: string;
autoComplete?: string; autoComplete?: string;
handleChange?: (value: string) => void; lowercase?: boolean;
handleFocus?: () => void; trim?: boolean;
onChange?: (value: string) => void;
onFocus?: () => void;
} }
function Input({ function Input({
@@ -23,14 +25,33 @@ function Input({
readOnly, readOnly,
className, className,
autoComplete, autoComplete,
handleChange, onChange,
handleFocus, onFocus,
lowercase,
trim,
}: InputProps) { }: InputProps) {
const [_value, setValue] = useState(value);
const inputRef = useMask({ const inputRef = useMask({
mask: "+7 (___) ___-__-__", mask: "+7 (___) ___-__-__",
replacement: { _: /\d/ }, replacement: { _: /\d/ },
}); });
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
let value = e.target.value;
if (lowercase) {
value = value.toLowerCase();
}
if (trim) {
value = value.trim();
}
setValue(value);
onChange?.(value);
};
return ( return (
<input <input
autoComplete={autoComplete} autoComplete={autoComplete}
@@ -40,9 +61,9 @@ function Input({
autoFocus={autoFocus} autoFocus={autoFocus}
required={required} required={required}
readOnly={readOnly} readOnly={readOnly}
value={value} value={_value}
onChange={(e) => handleChange && handleChange(e.target.value)} onChange={handleChange}
onFocus={handleFocus} onFocus={onFocus}
className={`px-3 py-[9px] outline-none rounded-lg ring-1 ring-[#DAE0E5] focus:ring-[#49A1F5] ring-inset transition-all text-sm ${className}`} className={`px-3 py-[9px] outline-none rounded-lg ring-1 ring-[#DAE0E5] focus:ring-[#49A1F5] ring-inset transition-all text-sm ${className}`}
/> />
); );
+7 -5
View File
@@ -318,7 +318,7 @@ function Schedule({ selectedDay, slots, events }: Props) {
<Input <Input
type="time" type="time"
value={startTime} value={startTime}
handleChange={(value) => setStartTime(value)} onChange={(value) => setStartTime(value)}
className="w-full" className="w-full"
/> />
</div> </div>
@@ -328,7 +328,7 @@ function Schedule({ selectedDay, slots, events }: Props) {
<Input <Input
type="time" type="time"
value={endTime} value={endTime}
handleChange={(value) => setEndTime(value)} onChange={(value) => setEndTime(value)}
className="w-full" className="w-full"
/> />
</div> </div>
@@ -344,10 +344,12 @@ function Schedule({ selectedDay, slots, events }: Props) {
<div className="space-y-1"> <div className="space-y-1">
<Label value="Email" /> <Label value="Email" />
<Input <Input
lowercase
trim
type="email" type="email"
className="w-full h-10" className="w-full h-10"
value={email} value={email}
handleChange={(value) => setEmail(value)} onChange={(value) => setEmail(value)}
/> />
<span className="text-[#77828C] text-xs"> <span className="text-[#77828C] text-xs">
На указанный почтовый адрес придет необходимая для На указанный почтовый адрес придет необходимая для
@@ -360,7 +362,7 @@ function Schedule({ selectedDay, slots, events }: Props) {
type="tel" type="tel"
className="w-full h-10" className="w-full h-10"
value={phone} value={phone}
handleChange={(value) => setPhone(value)} onChange={(value) => setPhone(value)}
/> />
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
@@ -368,7 +370,7 @@ function Schedule({ selectedDay, slots, events }: Props) {
<Input <Input
className="w-full h-10" className="w-full h-10"
value={name} value={name}
handleChange={(value) => setName(value)} onChange={(value) => setName(value)}
/> />
</div> </div>
</div> </div>
+1 -1
View File
@@ -32,7 +32,7 @@ function Select({ defaultValue, options, handleChange }: SelectProps) {
<div ref={selectRef} className="relative"> <div ref={selectRef} className="relative">
<Input <Input
readOnly readOnly
handleFocus={() => setIsShow(true)} onFocus={() => setIsShow(true)}
value={options?.find((option) => option.value === value).text} value={options?.find((option) => option.value === value).text}
className="w-full cursor-pointer" className="w-full cursor-pointer"
/> />
@@ -107,21 +107,23 @@ function AddManagerModal() {
<div className="space-y-1"> <div className="space-y-1">
<Label value="Email*" /> <Label value="Email*" />
<Input <Input
required
autoFocus
lowercase
trim
type="email" type="email"
className="w-full" className="w-full"
autoFocus
required
value={username} value={username}
handleChange={(value) => setUsername(value)} onChange={(value) => setUsername(value)}
/> />
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
<Label value="Имя*" /> <Label value="Имя*" />
<Input <Input
className="w-full"
required required
className="w-full"
value={name} value={name}
handleChange={(value) => setName(value)} onChange={(value) => setName(value)}
/> />
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
@@ -146,7 +146,7 @@ function CompanyModal() {
<Input <Input
type="time" type="time"
value={startTime} value={startTime}
handleChange={(value) => setStartTime(value)} onChange={(value) => setStartTime(value)}
/> />
</div> </div>
<p className="text-[#77828C] mt-4">-</p> <p className="text-[#77828C] mt-4">-</p>
@@ -155,7 +155,7 @@ function CompanyModal() {
<Input <Input
type="time" type="time"
value={endTime} value={endTime}
handleChange={(value) => setEndTime(value)} onChange={(value) => setEndTime(value)}
/> />
</div> </div>
</div> </div>
@@ -50,13 +50,14 @@ function CreateBuildModal({ companyId }: Props) {
<p className="text-xl font-semibold">Создание ЖК</p> <p className="text-xl font-semibold">Создание ЖК</p>
<form onSubmit={handleSubmit} className="flex flex-col gap-4"> <form onSubmit={handleSubmit} className="flex flex-col gap-4">
<Input <Input
required
autoFocus
placeholder="Название ЖК" placeholder="Название ЖК"
className="w-64" className="w-64"
handleChange={(value) => setName(value)} onChange={(value) => setName(value)}
autoFocus
required
/> />
<Select3 <Select3
required
options={[ options={[
"nksJukovaDev", "nksJukovaDev",
"Avgust", "Avgust",
@@ -89,7 +90,6 @@ function CreateBuildModal({ companyId }: Props) {
"Zoolog", "Zoolog",
]} ]}
onSelect={(option) => setBuild(option)} onSelect={(option) => setBuild(option)}
required
/> />
<div className="flex self-end gap-2"> <div className="flex self-end gap-2">
<Button variant="secondary" onClick={() => setModal(null)}> <Button variant="secondary" onClick={() => setModal(null)}>
@@ -44,19 +44,19 @@ function CreateCompanyModal() {
<p className="text-xl font-semibold">Создание компании</p> <p className="text-xl font-semibold">Создание компании</p>
<form onSubmit={handleSubmit} className="flex flex-col gap-4"> <form onSubmit={handleSubmit} className="flex flex-col gap-4">
<Input <Input
required
autoFocus
placeholder="Название компании" placeholder="Название компании"
className="w-64" className="w-64"
handleChange={(value) => setName(value)} onChange={(value) => setName(value)}
autoFocus
required
/> />
<Input <Input
required
type="number"
placeholder="Кол-во серверов" placeholder="Кол-во серверов"
className="w-64" className="w-64"
type="number"
required
value={sessionLimit?.toString()} value={sessionLimit?.toString()}
handleChange={(value) => setSessionLimit(+value)} onChange={(value) => setSessionLimit(+value)}
/> />
<div className="flex self-end gap-2"> <div className="flex self-end gap-2">
<Button variant="secondary" onClick={() => setModal(null)}> <Button variant="secondary" onClick={() => setModal(null)}>
@@ -160,7 +160,7 @@ function CreateScheduleModal() {
<Input <Input
type="time" type="time"
value={startTime} value={startTime}
handleChange={(value) => setStartTime(value)} onChange={(value) => setStartTime(value)}
className="w-[137px]" className="w-[137px]"
/> />
</div> </div>
@@ -170,7 +170,7 @@ function CreateScheduleModal() {
<Input <Input
type="time" type="time"
value={endTime} value={endTime}
handleChange={changeEndTime} onChange={changeEndTime}
className="w-[137px]" className="w-[137px]"
/> />
</div> </div>
@@ -106,10 +106,12 @@ function CreateScheduledSessionModal({ buildId, startAt, duration }: Props) {
<div className="space-y-1"> <div className="space-y-1">
<Label value="Email" /> <Label value="Email" />
<Input <Input
lowercase
trim
type="email" type="email"
className="h-10" className="h-10"
value={email} value={email}
handleChange={(value) => setEmail(value)} onChange={(value) => setEmail(value)}
/> />
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
@@ -118,7 +120,7 @@ function CreateScheduledSessionModal({ buildId, startAt, duration }: Props) {
type="tel" type="tel"
className="h-10" className="h-10"
value={phone} value={phone}
handleChange={(value) => setPhone(value)} onChange={(value) => setPhone(value)}
/> />
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
@@ -126,7 +128,7 @@ function CreateScheduledSessionModal({ buildId, startAt, duration }: Props) {
<Input <Input
className="h-10" className="h-10"
value={name} value={name}
handleChange={(value) => setName(value)} onChange={(value) => setName(value)}
/> />
</div> </div>
</div> </div>
@@ -97,25 +97,27 @@ function CreateUserModal({ companyId }: Props) {
<p className="text-xl font-semibold">Новый пользователь</p> <p className="text-xl font-semibold">Новый пользователь</p>
<form onSubmit={handleSubmit} className="flex flex-col gap-4"> <form onSubmit={handleSubmit} className="flex flex-col gap-4">
<Input <Input
required
autoFocus
placeholder="Имя Фамилия" placeholder="Имя Фамилия"
className="w-64" className="w-64"
handleChange={(value) => setName(value)} onChange={(value) => setName(value)}
autoFocus
required
/> />
<Input <Input
required
lowercase
trim
placeholder="Email (Логин)" placeholder="Email (Логин)"
className="w-64" className="w-64"
handleChange={(value) => setUsername(value)} onChange={(value) => setUsername(value)}
required
/> />
<Input <Input
required
autoComplete="new-password" autoComplete="new-password"
type="password" type="password"
placeholder="Пароль" placeholder="Пароль"
className="w-64" className="w-64"
handleChange={(value) => setPassword(value)} onChange={(value) => setPassword(value)}
required
/> />
<select <select
className="px-3 py-2 border border-gray-300 rounded-lg outline-none" className="px-3 py-2 border border-gray-300 rounded-lg outline-none"
@@ -126,14 +126,14 @@ function EditUserModal({ companyId, userId }: Props) {
placeholder="Имя Фамилия" placeholder="Имя Фамилия"
className="w-64" className="w-64"
value={name} value={name}
handleChange={(value) => setName(value)} onChange={(value) => setName(value)}
required required
/> />
<Input <Input
placeholder="Email (Логин)" placeholder="Email (Логин)"
className="w-64" className="w-64"
value={username} value={username}
handleChange={(value) => setUsername(value)} onChange={(value) => setUsername(value)}
required required
/> />
<select <select
@@ -95,7 +95,7 @@ function SettingsModal() {
required required
className="w-full" className="w-full"
value={oldPassword} value={oldPassword}
handleChange={(value) => setOldPassword(value)} onChange={(value) => setOldPassword(value)}
/> />
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
@@ -105,7 +105,7 @@ function SettingsModal() {
required required
className="w-full" className="w-full"
value={newPassword} value={newPassword}
handleChange={(value) => setNewPassword(value)} onChange={(value) => setNewPassword(value)}
/> />
</div> </div>
<Button <Button
+4 -2
View File
@@ -54,11 +54,13 @@ function LoginPage() {
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<Label value="Email" /> <Label value="Email" />
<Input <Input
lowercase
trim
type="email" type="email"
placeholder="example@gmail.com" placeholder="example@gmail.com"
autoFocus autoFocus
required required
handleChange={(value) => setUsername(value)} onChange={(value) => setUsername(value)}
/> />
</div> </div>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
@@ -67,7 +69,7 @@ function LoginPage() {
type="password" type="password"
placeholder="********" placeholder="********"
required required
handleChange={(value) => setPassword(value)} onChange={(value) => setPassword(value)}
/> />
</div> </div>
<Button <Button
@@ -66,7 +66,7 @@ function ResetPasswordConfirmPage() {
autoFocus autoFocus
required required
value={password} value={password}
handleChange={(value) => setPassword(value)} onChange={(value) => setPassword(value)}
/> />
</div> </div>
</div> </div>
+3 -1
View File
@@ -60,11 +60,13 @@ function ResetPasswordPage() {
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<Label value="Email" /> <Label value="Email" />
<Input <Input
lowercase
trim
type="email" type="email"
placeholder="mail@example.com" placeholder="mail@example.com"
autoFocus autoFocus
required required
handleChange={(value) => setUsername(value)} onChange={(value) => setUsername(value)}
/> />
</div> </div>
</div> </div>
+2
View File
@@ -6,6 +6,8 @@ const userSchema = new Schema(
type: String, type: String,
required: true, required: true,
unique: true, unique: true,
trim: true,
lowercase: true,
}, },
password: { password: {
type: String, type: String,
+5 -2
View File
@@ -8,13 +8,16 @@ import { createSecretKey } from "crypto";
const router = Router(); const router = Router();
router.post("/", async (req, res) => { router.post("/", async (req, res) => {
const { username, password } = req.body; const username = req.body.username.toLowerCase().trim();
const { password } = req.body;
if (!username || !password) { if (!username || !password) {
return res.json({ error: "Неверный логин или пароль" }); return res.json({ error: "Неверный логин или пароль" });
} }
const user = await User.findOne({ username }).lean(); const user = await User.findOne({
username: { $regex: new RegExp(username, "i") },
}).lean();
if (!user) { if (!user) {
return res.json({ error: "Неверный логин или пароль" }); return res.json({ error: "Неверный логин или пароль" });