updata
This commit is contained in:
@@ -74,7 +74,8 @@ function ChangePassword() {
|
||||
<AuthPasswordInput
|
||||
name="password"
|
||||
placeholder="کلمه عبور جدید"
|
||||
className={`border mt-4 ${
|
||||
wrapperClassName="mt-4"
|
||||
className={`border ${
|
||||
formik.touched.password && formik.errors.password
|
||||
? "border-red-500 dark:border-red-500"
|
||||
: "border-gray-300"
|
||||
@@ -92,7 +93,8 @@ function ChangePassword() {
|
||||
<AuthPasswordInput
|
||||
name="confirmPassword"
|
||||
placeholder="تکرار کلمه عبور"
|
||||
className={`border mt-4 ${
|
||||
wrapperClassName="mt-4"
|
||||
className={`border ${
|
||||
formik.touched.confirmPassword && formik.errors.confirmPassword
|
||||
? "border-red-500 dark:border-red-500"
|
||||
: "border-gray-300"
|
||||
@@ -107,8 +109,8 @@ function ChangePassword() {
|
||||
</small>
|
||||
)}
|
||||
|
||||
<AuthButton type="submit" className="mt-5" disabled={loading}>
|
||||
{loading ? "در حال ارسال..." : "تغییر کلمه عبور"}
|
||||
<AuthButton type="submit" className="mt-5" loading={loading} disabled={loading}>
|
||||
تغییر کلمه عبور
|
||||
</AuthButton>
|
||||
</form>
|
||||
|
||||
|
||||
@@ -96,9 +96,9 @@ function ForgetPasswordOtp() {
|
||||
<AuthButton
|
||||
type="submit"
|
||||
className="mt-5"
|
||||
disabled={loading || otpExpired || formik.values.otp.length !== 6}
|
||||
loading={loading} disabled={loading || otpExpired || formik.values.otp.length !== 6}
|
||||
>
|
||||
{loading ? "در حال ارسال..." : "تایید کد"}
|
||||
تایید کد
|
||||
</AuthButton>
|
||||
</form>
|
||||
<Link href={"/login-with-username"}>
|
||||
|
||||
@@ -6,6 +6,7 @@ import AuthInput from "@/components/auth/AuthInput";
|
||||
import Container from "@/components/elements/Container";
|
||||
import Link from "next/link";
|
||||
import React from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
import { useFormik } from "formik";
|
||||
import * as yup from "yup";
|
||||
@@ -52,6 +53,7 @@ function ForgetPassword() {
|
||||
name="mobile"
|
||||
maxLength={11}
|
||||
type="text"
|
||||
dir="ltr"
|
||||
placeholder="09 _ _ _ _ _ _ _ _ _"
|
||||
className={`border ${
|
||||
formik.touched.mobile && formik.errors.mobile
|
||||
@@ -67,8 +69,8 @@ function ForgetPassword() {
|
||||
{formik.errors.mobile}
|
||||
</small>
|
||||
)}
|
||||
<AuthButton type="submit" className="mt-5" disabled={loading}>
|
||||
{loading ? "در حال ارسال..." : "ارسال کد"}
|
||||
<AuthButton type="submit" className="mt-5" loading={loading} disabled={loading}>
|
||||
ارسال کد
|
||||
</AuthButton>
|
||||
</form>
|
||||
<Link href={"/register"}>
|
||||
|
||||
@@ -104,7 +104,8 @@ function LoginWithUsername() {
|
||||
<AuthPasswordInput
|
||||
name="password"
|
||||
placeholder="کلمه عبور"
|
||||
className={`border mt-4 ${
|
||||
wrapperClassName="mt-4"
|
||||
className={`border ${
|
||||
formik.touched.password && formik.errors.password
|
||||
? "border-red-500 dark:border-red-500"
|
||||
: "border-gray-300"
|
||||
@@ -118,8 +119,8 @@ function LoginWithUsername() {
|
||||
{formik.errors.password}
|
||||
</small>
|
||||
)}
|
||||
<AuthButton type="submit" className="mt-5" disabled={loading}>
|
||||
{loading ? "در حال ارسال..." : "ورود"}
|
||||
<AuthButton type="submit" className="mt-5" loading={loading} disabled={loading}>
|
||||
ورود
|
||||
</AuthButton>
|
||||
</form>
|
||||
<Link href={"/forget-password"}>
|
||||
|
||||
@@ -10,6 +10,7 @@ import React, { useState } from "react";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
import { useFormik } from "formik";
|
||||
import * as yup from "yup";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { markOtpSent } from "@/lib/auth/otpTimer";
|
||||
|
||||
// Validation schema using Yup
|
||||
@@ -54,7 +55,8 @@ function Login() {
|
||||
name="mobile"
|
||||
maxLength={11}
|
||||
type="tel"
|
||||
pattern="[0-9]*"
|
||||
pattern="[0-9]*"
|
||||
dir="ltr"
|
||||
placeholder="09 _ _ _ _ _ _ _ _ _"
|
||||
className={`border ${
|
||||
formik.touched.mobile && formik.errors.mobile
|
||||
@@ -70,8 +72,8 @@ function Login() {
|
||||
{formik.errors.mobile}
|
||||
</small>
|
||||
)}
|
||||
<AuthButton type="submit" className="mt-5" disabled={loading}>
|
||||
{loading ? "در حال ارسال..." : "ارسال کد"}
|
||||
<AuthButton type="submit" className="mt-5" loading={loading} disabled={loading}>
|
||||
ارسال کد
|
||||
</AuthButton>
|
||||
</form>
|
||||
<Link href={"/login-with-username"}>
|
||||
|
||||
@@ -133,9 +133,9 @@ function VerifyOtp() {
|
||||
<AuthButton
|
||||
type="submit"
|
||||
className="mt-5"
|
||||
disabled={loading || otpExpired || formik.values.otp.length !== 6}
|
||||
loading={loading} disabled={loading || otpExpired || formik.values.otp.length !== 6}
|
||||
>
|
||||
{loading ? "در حال ارسال..." : "تایید کد"}
|
||||
تایید کد
|
||||
</AuthButton>
|
||||
</form>
|
||||
<Link href={"/login-with-username"}>
|
||||
|
||||
@@ -105,9 +105,9 @@ function RegisterOtp() {
|
||||
<AuthButton
|
||||
type="submit"
|
||||
className="mt-5"
|
||||
disabled={loading || otpExpired || formik.values.otp.length !== 6}
|
||||
loading={loading} disabled={loading || otpExpired || formik.values.otp.length !== 6}
|
||||
>
|
||||
{loading ? "در حال ارسال..." : "تایید کد"}
|
||||
تایید کد
|
||||
</AuthButton>
|
||||
</form>
|
||||
<Link href={"/forget-password"}>
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
|
||||
import AuthHead from "@/components/auth/AuthHead";
|
||||
import AuthInput from "@/components/auth/AuthInput";
|
||||
import Container from "@/components/elements/Container";
|
||||
import AuthPageLayout, {
|
||||
AuthFormFooter,
|
||||
AuthPageContent,
|
||||
} from "@/components/auth/AuthPageLayout";
|
||||
import React from "react";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
import { useFormik } from "formik";
|
||||
@@ -45,17 +48,19 @@ function FullNamePage() {
|
||||
});
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className="p-4 flex flex-col items-center h-screen justify-center">
|
||||
<AuthHead title="نام و نام خانوادگی" />
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
className="w-full max-w-sm flex flex-col items-center"
|
||||
>
|
||||
<AuthPageLayout>
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
className="flex w-full flex-1 flex-col items-center"
|
||||
>
|
||||
<AuthPageContent>
|
||||
<AuthHead title="نام و نام خانوادگی" />
|
||||
<div className="w-full max-w-sm flex flex-col items-center">
|
||||
<AuthInput
|
||||
name="name"
|
||||
type="text"
|
||||
placeholder="نام"
|
||||
dir="rtl"
|
||||
className={`border mt-4 ${
|
||||
formik.touched.name && formik.errors.name
|
||||
? "border-red-500 dark:border-red-500"
|
||||
@@ -66,7 +71,7 @@ function FullNamePage() {
|
||||
onBlur={formik.handleBlur}
|
||||
/>
|
||||
{formik.touched.name && formik.errors.name && (
|
||||
<small className="text-red-500 mt-2 block">
|
||||
<small className="text-red-500 mt-2 block text-center">
|
||||
{formik.errors.name}
|
||||
</small>
|
||||
)}
|
||||
@@ -75,6 +80,7 @@ function FullNamePage() {
|
||||
name="family"
|
||||
type="text"
|
||||
placeholder="نام خانوادگی"
|
||||
dir="rtl"
|
||||
className={`border mt-4 ${
|
||||
formik.touched.family && formik.errors.family
|
||||
? "border-red-500 dark:border-red-500"
|
||||
@@ -85,17 +91,20 @@ function FullNamePage() {
|
||||
onBlur={formik.handleBlur}
|
||||
/>
|
||||
{formik.touched.family && formik.errors.family && (
|
||||
<small className="text-red-500 mt-2 block">
|
||||
<small className="text-red-500 mt-2 block text-center">
|
||||
{formik.errors.family}
|
||||
</small>
|
||||
)}
|
||||
</div>
|
||||
</AuthPageContent>
|
||||
|
||||
<AuthNextButton type="submit" className="mt-20" disabled={loading}>
|
||||
{loading ? "در حال ارسال..." : "ثبت و ادامه"}
|
||||
<AuthFormFooter>
|
||||
<AuthNextButton type="submit" loading={loading} disabled={loading}>
|
||||
ثبت و ادامه
|
||||
</AuthNextButton>
|
||||
</form>
|
||||
</div>
|
||||
</Container>
|
||||
</AuthFormFooter>
|
||||
</form>
|
||||
</AuthPageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import React, { useState } from "react";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
import { useFormik } from "formik";
|
||||
import * as yup from "yup";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { markOtpSent } from "@/lib/auth/otpTimer";
|
||||
|
||||
// Validation schema using Yup
|
||||
@@ -53,6 +54,7 @@ function Register() {
|
||||
name="mobile"
|
||||
maxLength={11}
|
||||
type="text"
|
||||
dir="ltr"
|
||||
placeholder="09 _ _ _ _ _ _ _ _ _"
|
||||
className={`border ${
|
||||
formik.touched.mobile && formik.errors.mobile
|
||||
@@ -68,8 +70,8 @@ function Register() {
|
||||
{formik.errors.mobile}
|
||||
</small>
|
||||
)}
|
||||
<AuthButton type="submit" className="mt-5" disabled={loading}>
|
||||
{loading ? "در حال ارسال..." : "ارسال کد"}
|
||||
<AuthButton type="submit" className="mt-5" loading={loading} disabled={loading}>
|
||||
ارسال کد
|
||||
</AuthButton>
|
||||
</form>
|
||||
<button onClick={() => setModalOpen(true)} className="mb-2">
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
|
||||
import AuthHead from "@/components/auth/AuthHead";
|
||||
import AuthPasswordInput from "@/components/auth/AuthPasswordInput";
|
||||
import Container from "@/components/elements/Container";
|
||||
import AuthPageLayout, {
|
||||
AuthFormFooter,
|
||||
AuthPageContent,
|
||||
} from "@/components/auth/AuthPageLayout";
|
||||
import React from "react";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
import { useFormik } from "formik";
|
||||
@@ -61,17 +64,19 @@ function PasswordPage() {
|
||||
});
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className="p-4 flex flex-col items-center h-screen justify-center">
|
||||
<AuthHead title="کلمه عبور" />
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
className="w-full max-w-sm flex flex-col items-center"
|
||||
>
|
||||
<AuthPageLayout>
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
className="flex w-full flex-1 flex-col items-center"
|
||||
>
|
||||
<AuthPageContent>
|
||||
<AuthHead title="کلمه عبور" />
|
||||
<div className="w-full max-w-sm flex flex-col items-center">
|
||||
<AuthPasswordInput
|
||||
name="password"
|
||||
placeholder="کلمه عبور"
|
||||
className={`border mt-4 ${
|
||||
wrapperClassName="mt-4"
|
||||
className={`border ${
|
||||
formik.touched.password && formik.errors.password
|
||||
? "border-red-500 dark:border-red-500"
|
||||
: "border-gray-300"
|
||||
@@ -89,7 +94,8 @@ function PasswordPage() {
|
||||
<AuthPasswordInput
|
||||
name="confirmPassword"
|
||||
placeholder="تکرار کلمه عبور"
|
||||
className={`border mt-4 ${
|
||||
wrapperClassName="mt-4"
|
||||
className={`border ${
|
||||
formik.touched.confirmPassword && formik.errors.confirmPassword
|
||||
? "border-red-500 dark:border-red-500"
|
||||
: "border-gray-300"
|
||||
@@ -103,13 +109,16 @@ function PasswordPage() {
|
||||
{formik.errors.confirmPassword}
|
||||
</small>
|
||||
)}
|
||||
</div>
|
||||
</AuthPageContent>
|
||||
|
||||
<AuthNextButton type="submit" className="mt-20" disabled={loading}>
|
||||
{loading ? "در حال ارسال..." : "تایید کلمه عبور"}
|
||||
<AuthFormFooter>
|
||||
<AuthNextButton type="submit" loading={loading} disabled={loading}>
|
||||
تایید کلمه عبور
|
||||
</AuthNextButton>
|
||||
</form>
|
||||
</div>
|
||||
</Container>
|
||||
</AuthFormFooter>
|
||||
</form>
|
||||
</AuthPageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
|
||||
import AuthHead from "@/components/auth/AuthHead";
|
||||
import AuthInput from "@/components/auth/AuthInput";
|
||||
import Container from "@/components/elements/Container";
|
||||
import AuthPageLayout, {
|
||||
AuthFormFooter,
|
||||
AuthPageContent,
|
||||
} from "@/components/auth/AuthPageLayout";
|
||||
import React, { useState } from "react";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
import { useFormik } from "formik";
|
||||
@@ -12,12 +15,12 @@ import { IVerifyOtp } from "@/types/types";
|
||||
import AuthNextButton from "@/components/auth/AuthNextButton";
|
||||
import UsernameSuggestions from "@/components/auth/UsernameSuggestions";
|
||||
import { usernameFormSchema } from "@/lib/validation/usernameSchema";
|
||||
import { sanitizeUsernameInput } from "@/lib/validation/username";
|
||||
import { sanitizeUsernameInput, USERNAME_MIN_LENGTH } from "@/lib/validation/username";
|
||||
|
||||
function UsernamePage() {
|
||||
const router = useRouter();
|
||||
const { request, loading } = useAxios();
|
||||
const [duplicateError, setDuplicateError] = useState<string | null>(null);
|
||||
const [isDuplicate, setIsDuplicate] = useState(false);
|
||||
const [suggestions, setSuggestions] = useState<string[]>([]);
|
||||
const mobile =
|
||||
typeof window !== "undefined" ? localStorage.getItem("mobile") : null;
|
||||
@@ -28,7 +31,7 @@ function UsernamePage() {
|
||||
},
|
||||
validationSchema: usernameFormSchema,
|
||||
onSubmit: async (values) => {
|
||||
setDuplicateError(null);
|
||||
setIsDuplicate(false);
|
||||
setSuggestions([]);
|
||||
|
||||
try {
|
||||
@@ -41,16 +44,18 @@ function UsernamePage() {
|
||||
router.push("/register/password");
|
||||
} catch (err: any) {
|
||||
const data = err?.response?.data;
|
||||
if (data?.message) {
|
||||
setDuplicateError(data.message);
|
||||
if (data?.message?.includes("تکراری")) {
|
||||
setIsDuplicate(true);
|
||||
setSuggestions(Array.isArray(data.suggestions) ? data.suggestions : []);
|
||||
} else if (data?.message) {
|
||||
formik.setFieldError("username", data.message);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const handleUsernameChange = (value: string) => {
|
||||
setDuplicateError(null);
|
||||
setIsDuplicate(false);
|
||||
setSuggestions([]);
|
||||
formik.setFieldValue("username", sanitizeUsernameInput(value));
|
||||
};
|
||||
@@ -58,27 +63,28 @@ function UsernamePage() {
|
||||
const handleSuggestionSelect = (username: string) => {
|
||||
formik.setFieldValue("username", username);
|
||||
formik.setFieldTouched("username", true, false);
|
||||
setDuplicateError(null);
|
||||
setIsDuplicate(false);
|
||||
setSuggestions([]);
|
||||
};
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className="p-4 flex flex-col items-center h-screen justify-center">
|
||||
<AuthHead title="نام کاربری" />
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
className="w-full max-w-sm flex flex-col items-center"
|
||||
>
|
||||
<AuthPageLayout>
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
className="flex w-full flex-1 flex-col items-center"
|
||||
>
|
||||
<AuthPageContent>
|
||||
<AuthHead title="نام کاربری" />
|
||||
<div className="w-full max-w-sm flex flex-col items-center">
|
||||
<AuthInput
|
||||
name="username"
|
||||
type="text"
|
||||
placeholder="example_user"
|
||||
placeholder="نام کاربری"
|
||||
dir="ltr"
|
||||
autoComplete="username"
|
||||
spellCheck={false}
|
||||
className={`border ${
|
||||
(formik.touched.username && formik.errors.username) || duplicateError
|
||||
(formik.touched.username && formik.errors.username) || isDuplicate
|
||||
? "border-red-500 dark:border-red-500"
|
||||
: "border-gray-300"
|
||||
}`}
|
||||
@@ -86,29 +92,37 @@ function UsernamePage() {
|
||||
onChange={(e) => handleUsernameChange(e.target.value)}
|
||||
onBlur={formik.handleBlur}
|
||||
/>
|
||||
<small className="text-gray-500 dark:text-gray-400 text-xs mt-2 text-center leading-5">
|
||||
فقط حروف انگلیسی، اعداد و کاراکترهای . _ - (حداقل ۶ کاراکتر)
|
||||
</small>
|
||||
{formik.touched.username && formik.errors.username && !duplicateError && (
|
||||
<small className="text-red-500 mt-2 block">
|
||||
|
||||
{isDuplicate && (
|
||||
<small className="text-red-500 mt-2 block text-center font-medium">
|
||||
نام کاربری تکراری است
|
||||
</small>
|
||||
)}
|
||||
|
||||
{formik.touched.username && formik.errors.username && !isDuplicate && (
|
||||
<small className="text-red-500 mt-2 block text-center">
|
||||
{formik.errors.username}
|
||||
</small>
|
||||
)}
|
||||
|
||||
<UsernameSuggestions
|
||||
message={duplicateError || undefined}
|
||||
suggestions={suggestions}
|
||||
onSelect={handleSuggestionSelect}
|
||||
/>
|
||||
</div>
|
||||
</AuthPageContent>
|
||||
|
||||
<AuthFormFooter>
|
||||
<AuthNextButton
|
||||
type="submit"
|
||||
className="mt-20"
|
||||
disabled={loading || formik.values.username.length < 6}
|
||||
loading={loading}
|
||||
disabled={loading || formik.values.username.length < USERNAME_MIN_LENGTH}
|
||||
>
|
||||
{loading ? "در حال ارسال..." : "ثبت و ادامه"}
|
||||
ثبت و ادامه
|
||||
</AuthNextButton>
|
||||
</form>
|
||||
</div>
|
||||
</Container>
|
||||
</AuthFormFooter>
|
||||
</form>
|
||||
</AuthPageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
"use client";
|
||||
|
||||
import AuthHead from "@/components/auth/AuthHead";
|
||||
import Container from "@/components/elements/Container";
|
||||
import AuthPageLayout, {
|
||||
AuthFormFooter,
|
||||
AuthPageContent,
|
||||
} from "@/components/auth/AuthPageLayout";
|
||||
import React, { useState } from "react";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
import { useFormik } from "formik";
|
||||
@@ -58,14 +61,14 @@ function UsertypePage() {
|
||||
});
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className="p-4 flex flex-col items-center h-screen justify-center">
|
||||
{/* <AuthHead title="نوع کاربری" /> */}
|
||||
<AuthHead title="" />
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
className="w-full max-w-sm flex flex-col items-center"
|
||||
>
|
||||
<AuthPageLayout>
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
className="flex w-full flex-1 flex-col items-center"
|
||||
>
|
||||
<AuthPageContent>
|
||||
<AuthHead title="" />
|
||||
<div className="w-full max-w-sm flex flex-col items-center">
|
||||
{/* User Type Buttons */}
|
||||
{/* <AuthNextButton
|
||||
type="button"
|
||||
@@ -90,35 +93,36 @@ function UsertypePage() {
|
||||
کارفرما
|
||||
</AuthNextButton> */}
|
||||
|
||||
{/* Error Message */}
|
||||
{formik.errors.selectedButton && formik.touched.selectedButton && (
|
||||
<div className="text-red-500 mt-2 text-sm">
|
||||
{formik.errors.selectedButton}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</AuthPageContent>
|
||||
|
||||
{/* Submit Buttons */}
|
||||
<AuthFormFooter>
|
||||
<div className="flex gap-3">
|
||||
<AuthNextButton
|
||||
type="submit"
|
||||
onClick={() => setSubmitAction("register")}
|
||||
className="mt-20 !border-[#0C8002] !text-[#0C8002]"
|
||||
className="!border-[#0C8002] !text-[#0C8002]"
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? "در حال ارسال..." : "ادامه ثبت نام"}
|
||||
ادامه ثبت نام
|
||||
</AuthNextButton>
|
||||
<AuthNextButton
|
||||
type="submit"
|
||||
onClick={() => setSubmitAction("login")}
|
||||
className="mt-20 !border-[#FF0000] !text-[#FF0000]"
|
||||
className="!border-[#FF0000] !text-[#FF0000]"
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? "در حال ارسال..." : "ورود به برنامه"}
|
||||
ورود به برنامه
|
||||
</AuthNextButton>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</Container>
|
||||
</AuthFormFooter>
|
||||
</form>
|
||||
</AuthPageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
"use client";
|
||||
|
||||
import Container from "@/components/elements/Container";
|
||||
import AuthPageLayout, {
|
||||
AuthFormFooter,
|
||||
AuthPageContent,
|
||||
} from "@/components/auth/AuthPageLayout";
|
||||
import React from "react";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
import { useFormik } from "formik";
|
||||
@@ -69,17 +72,18 @@ function AuthPage() {
|
||||
console.log(formik.values);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className="p-4 flex flex-col items-center h-screen justify-center auth-page">
|
||||
<span className="text-xl font-bold">احراز هویت</span>
|
||||
<div className="mt-5">
|
||||
<AuthUserDetails />
|
||||
</div>
|
||||
<AuthPageLayout className="auth-page">
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
className="flex w-full flex-1 flex-col items-center"
|
||||
>
|
||||
<AuthPageContent>
|
||||
<span className="text-xl font-bold">احراز هویت</span>
|
||||
<div className="mt-5">
|
||||
<AuthUserDetails />
|
||||
</div>
|
||||
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
className="w-full max-w-sm flex flex-col items-center"
|
||||
>
|
||||
<div className="w-full max-w-sm flex flex-col items-center">
|
||||
<small className="font-bold mt-10 mb-4"> جهت احراز هویت</small>
|
||||
<div className="flex w-full gap-2 max-w-[300px]">
|
||||
<div>
|
||||
@@ -165,19 +169,16 @@ function AuthPage() {
|
||||
<small className="font-bold mt-10">
|
||||
شماره شبا باید به نام خود شخص باشد
|
||||
</small>
|
||||
<AuthNextButton type="submit" className="mt-20" disabled={loading}>
|
||||
{loading ? "در حال ارسال..." : "ثبت و ادامه"}
|
||||
</div>
|
||||
</AuthPageContent>
|
||||
|
||||
<AuthFormFooter onSkip={() => router.push("/verify/location")}>
|
||||
<AuthNextButton type="submit" loading={loading} disabled={loading}>
|
||||
ثبت و ادامه
|
||||
</AuthNextButton>
|
||||
<button
|
||||
className="text-sm text-gray-500 mt-5"
|
||||
onClick={() => router.push("/verify/location")}
|
||||
type="button"
|
||||
>
|
||||
<span>رد کن</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</Container>
|
||||
</AuthFormFooter>
|
||||
</form>
|
||||
</AuthPageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect, useState, useCallback } from "react";
|
||||
import Container from "@/components/elements/Container";
|
||||
import AuthPageLayout, {
|
||||
AuthFormFooter,
|
||||
AuthPageContent,
|
||||
} from "@/components/auth/AuthPageLayout";
|
||||
import AuthNextButton from "@/components/auth/AuthNextButton";
|
||||
import { IMAGE_BASE_URL, buildStorageUrl } from "@/components/main/BaseUrl";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
@@ -20,7 +23,6 @@ function AvatarPage() {
|
||||
const { request, loading } = useAxios();
|
||||
const [userDetail, setUserDetail] = useState<IProfileData | null>(null);
|
||||
const [avatar, setAvatar] = useState<string | null>(null);
|
||||
const [originalImage, setOriginalImage] = useState<string | null>(null); // تصویر اصلی (سایز کامل)
|
||||
const [crop, setCrop] = useState({ x: 0, y: 0 });
|
||||
const [zoom, setZoom] = useState(1);
|
||||
const [loadingUpload, setLoadingUpload] = useState(false);
|
||||
@@ -50,8 +52,7 @@ function AvatarPage() {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
const imageDataUrl = e.target?.result as string;
|
||||
setAvatar(imageDataUrl); // برای کراپر
|
||||
setOriginalImage(imageDataUrl); // تصویر اصلی (سایز کامل)
|
||||
setAvatar(imageDataUrl);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
@@ -105,7 +106,6 @@ function AvatarPage() {
|
||||
} catch (err) {
|
||||
console.log("Upload error:", err);
|
||||
toast.error("خطا در ارسال تصویر!");
|
||||
} finally {
|
||||
setLoadingUpload(false);
|
||||
}
|
||||
};
|
||||
@@ -120,28 +120,11 @@ function AvatarPage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className="p-4 flex flex-col items-center h-screen justify-center">
|
||||
{(loading || loadingUpload) && <p>Loading...</p>}
|
||||
<AuthPageLayout>
|
||||
<AuthPageContent>
|
||||
<span className="text-xl font-bold mb-4">تصویر پروفایل</span>
|
||||
|
||||
{!loading && !loadingUpload && (
|
||||
<>
|
||||
<span className="text-xl font-bold mb-4">تصویر پروفایل</span>
|
||||
|
||||
{/* نمایش تصویر اصلی (سایز کامل) */}
|
||||
{originalImage && (
|
||||
<div className="relative w-[300px] h-[400px] bg-gray-200 rounded-2xl mb-4 overflow-hidden">
|
||||
<Image
|
||||
src={originalImage}
|
||||
alt="Original image"
|
||||
fill
|
||||
className="object-contain"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* کراپر برای برش تصویر به مربع 1:1 */}
|
||||
<div className="relative w-[250px] h-[250px] bg-gray-200 rounded-3xl overflow-hidden mb-4">
|
||||
<div className="relative aspect-square w-[250px] bg-gray-200 rounded-3xl overflow-hidden mb-4">
|
||||
{avatar ? (
|
||||
<Cropper
|
||||
image={avatar.startsWith("data:") ? avatar : IMAGE_BASE_URL + avatar}
|
||||
@@ -178,31 +161,26 @@ function AvatarPage() {
|
||||
onChange={selectImage}
|
||||
/>
|
||||
|
||||
<AuthNextButton className="mt-4">
|
||||
<label className="cursor-pointer w-full h-full" htmlFor="fileInput">
|
||||
انتخاب/ویرایش تصویر
|
||||
</label>
|
||||
</AuthNextButton>
|
||||
<AuthNextButton className="mt-4">
|
||||
<label className="cursor-pointer w-full h-full" htmlFor="fileInput">
|
||||
انتخاب/ویرایش تصویر
|
||||
</label>
|
||||
</AuthNextButton>
|
||||
</AuthPageContent>
|
||||
|
||||
<AuthNextButton
|
||||
onClick={uploadImage}
|
||||
className="mt-10"
|
||||
disabled={loadingUpload}
|
||||
>
|
||||
ثبت و ادامه
|
||||
</AuthNextButton>
|
||||
|
||||
<button
|
||||
className="text-sm text-gray-500 mt-5"
|
||||
onClick={navigateHandler}
|
||||
type="button"
|
||||
>
|
||||
رد کن
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</Container>
|
||||
<AuthFormFooter
|
||||
onSkip={navigateHandler}
|
||||
skipDisabled={loadingUpload}
|
||||
>
|
||||
<AuthNextButton
|
||||
onClick={uploadImage}
|
||||
loading={loadingUpload}
|
||||
disabled={loadingUpload}
|
||||
>
|
||||
ثبت و ادامه
|
||||
</AuthNextButton>
|
||||
</AuthFormFooter>
|
||||
</AuthPageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
"use client";
|
||||
|
||||
import Container from "@/components/elements/Container";
|
||||
import AuthPageLayout, {
|
||||
AuthFormFooter,
|
||||
AuthPageContent,
|
||||
} from "@/components/auth/AuthPageLayout";
|
||||
import React, { useState } from "react";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
import * as yup from "yup";
|
||||
@@ -88,8 +91,8 @@ function Colors() {
|
||||
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className="p-4 flex flex-col items-center h-screen justify-center">
|
||||
<AuthPageLayout>
|
||||
<AuthPageContent>
|
||||
<span className="text-xl font-bold">سایز</span>
|
||||
<div className="mt-5">
|
||||
<AuthUserDetails />
|
||||
@@ -163,24 +166,19 @@ function Colors() {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</AuthPageContent>
|
||||
|
||||
<AuthFormFooter onSkip={() => router.push("/verify/public-relations")}>
|
||||
<AuthNextButton
|
||||
type="button"
|
||||
onClick={handleCheck}
|
||||
className="mt-10"
|
||||
loading={loading}
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? "در حال ارسال..." : "ثبت و ادامه"}
|
||||
ثبت و ادامه
|
||||
</AuthNextButton>
|
||||
<button
|
||||
className="text-sm text-gray-500 mt-5"
|
||||
onClick={() => router.push("/verify/public-relations")}
|
||||
type="button"
|
||||
>
|
||||
<span>رد کن</span>
|
||||
</button>
|
||||
</div>
|
||||
</Container>
|
||||
</AuthFormFooter>
|
||||
</AuthPageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,20 +8,23 @@ import AuthNextButton from "@/components/auth/AuthNextButton";
|
||||
import Modal from "@/components/elements/Modal";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import ProfileAvatar from "@/components/main/ProfileAvatar";
|
||||
import { useUser } from "@/hooks/useUser";
|
||||
import { IMAGE_BASE_URL, buildStorageUrl } from "@/components/main/BaseUrl";
|
||||
|
||||
function Confirm() {
|
||||
|
||||
const user = useUser();
|
||||
const router = useRouter();
|
||||
const [showModal, setShowModal] = useState<boolean>(false);
|
||||
const [navigating, setNavigating] = useState(false);
|
||||
const userType: string | null =
|
||||
typeof window !== "undefined" ? localStorage.getItem("usertype") : null;
|
||||
|
||||
const confirmHandler = () => {
|
||||
setNavigating(true);
|
||||
if (userType !== "employer") {
|
||||
setShowModal(true);
|
||||
setNavigating(false);
|
||||
} else {
|
||||
router.push("/");
|
||||
}
|
||||
@@ -36,13 +39,11 @@ function Confirm() {
|
||||
ورود شما به خانواده مدستاگرام را تبریک می گوییم{" "}
|
||||
</small>
|
||||
<div className="flex flex-col justify-center items-center">
|
||||
<Image
|
||||
className="rounded-2xl object-cover"
|
||||
width={280}
|
||||
height={280}
|
||||
<ProfileAvatar
|
||||
src={user?.profile_image}
|
||||
alt={user?.user_name || "user profile"}
|
||||
src={buildStorageUrl(user?.profile_image)}
|
||||
unoptimized={true}
|
||||
size="xl"
|
||||
rounded="2xl"
|
||||
/>
|
||||
<div className="flex flex-col justify-center items-center gap-1 mt-1">
|
||||
<span>
|
||||
@@ -117,7 +118,7 @@ function Confirm() {
|
||||
</div>
|
||||
</div>
|
||||
{/* */}
|
||||
<AuthNextButton onClick={confirmHandler} className="mt-20">
|
||||
<AuthNextButton onClick={confirmHandler} className="mt-20" loading={navigating} disabled={navigating}>
|
||||
ثبت و ادامه
|
||||
</AuthNextButton>
|
||||
<small className="font-bold mt-10 mb-1 text-center">
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
"use client";
|
||||
|
||||
import Container from "@/components/elements/Container";
|
||||
import AuthPageLayout, {
|
||||
AuthFormFooter,
|
||||
AuthPageContent,
|
||||
} from "@/components/auth/AuthPageLayout";
|
||||
import React from "react";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
import { useFormik } from "formik";
|
||||
@@ -44,20 +47,22 @@ function CooperationType() {
|
||||
});
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className="p-4 flex flex-col items-center h-screen justify-center">
|
||||
<span className="text-xl font-bold">نوع همکاری</span>
|
||||
<div className="mt-5">
|
||||
<AuthUserDetails />
|
||||
</div>
|
||||
<AuthPageLayout>
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
className="flex w-full flex-1 flex-col items-center"
|
||||
>
|
||||
<AuthPageContent>
|
||||
<span className="text-xl font-bold">نوع همکاری</span>
|
||||
<div className="mt-5">
|
||||
<AuthUserDetails />
|
||||
</div>
|
||||
|
||||
<p className="my-10 text-sm font-bold">
|
||||
آیا مایل به همکاری خارج از محل سکونت خود هستید؟
|
||||
</p>
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
className="w-full max-w-sm flex flex-col items-center"
|
||||
>
|
||||
<p className="my-10 text-sm font-bold">
|
||||
آیا مایل به همکاری خارج از محل سکونت خود هستید؟
|
||||
</p>
|
||||
|
||||
<div className="w-full max-w-sm flex flex-col items-center">
|
||||
<div className="flex w-full gap-2">
|
||||
<AuthNextButton
|
||||
type="button"
|
||||
@@ -83,26 +88,21 @@ function CooperationType() {
|
||||
</AuthNextButton>
|
||||
</div>
|
||||
|
||||
{/* Error Message */}
|
||||
{formik.errors.selectedButton && formik.touched.selectedButton && (
|
||||
<div className="text-red-500 mt-2 text-sm">
|
||||
{formik.errors.selectedButton}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</AuthPageContent>
|
||||
|
||||
<AuthNextButton type="submit" className="mt-20" disabled={loading}>
|
||||
{loading ? "در حال ارسال..." : "ثبت و ادامه"}
|
||||
<AuthFormFooter onSkip={() => router.push("/verify/public-relations")}>
|
||||
<AuthNextButton type="submit" loading={loading} disabled={loading}>
|
||||
ثبت و ادامه
|
||||
</AuthNextButton>
|
||||
<button
|
||||
className="text-sm text-gray-500 mt-5"
|
||||
onClick={() => router.push("/verify/public-relations")}
|
||||
type="button"
|
||||
>
|
||||
<span>رد کن</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</Container>
|
||||
</AuthFormFooter>
|
||||
</form>
|
||||
</AuthPageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
"use client";
|
||||
|
||||
import Container from "@/components/elements/Container";
|
||||
import AuthPageLayout, {
|
||||
AuthFormFooter,
|
||||
AuthPageContent,
|
||||
} from "@/components/auth/AuthPageLayout";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
import * as yup from "yup";
|
||||
@@ -89,8 +92,8 @@ function Expertise() {
|
||||
);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className="p-4 flex flex-col items-center h-screen justify-center">
|
||||
<AuthPageLayout>
|
||||
<AuthPageContent>
|
||||
<span className="text-xl font-bold">تخصص</span>
|
||||
|
||||
<AuthUserDetails />
|
||||
@@ -126,25 +129,19 @@ function Expertise() {
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</AuthPageContent>
|
||||
|
||||
<AuthFormFooter onSkip={() => router.push("/verify/services")}>
|
||||
<AuthNextButton
|
||||
type="button"
|
||||
onClick={handleCheck}
|
||||
className="mt-20"
|
||||
loading={loading}
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? "در حال ارسال..." : "ثبت و ادامه"}
|
||||
ثبت و ادامه
|
||||
</AuthNextButton>
|
||||
|
||||
<button
|
||||
className="text-sm text-gray-500 mt-5"
|
||||
onClick={() => router.push("/verify/services")}
|
||||
type="button"
|
||||
>
|
||||
<span>رد کن</span>
|
||||
</button>
|
||||
</div>
|
||||
</Container>
|
||||
</AuthFormFooter>
|
||||
</AuthPageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
"use client";
|
||||
|
||||
import Container from "@/components/elements/Container";
|
||||
import AuthPageLayout, {
|
||||
AuthFormFooter,
|
||||
AuthPageContent,
|
||||
} from "@/components/auth/AuthPageLayout";
|
||||
import React from "react";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
import { useFormik } from "formik";
|
||||
@@ -50,16 +53,18 @@ function Gender() {
|
||||
});
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className="p-4 flex flex-col items-center h-screen justify-center">
|
||||
<span className="text-xl font-bold">جنسیت</span>
|
||||
<div className="mt-5">
|
||||
<AuthUserDetails />
|
||||
</div>
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
className="w-full max-w-sm flex flex-col items-center"
|
||||
>
|
||||
<AuthPageLayout>
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
className="flex w-full flex-1 flex-col items-center"
|
||||
>
|
||||
<AuthPageContent>
|
||||
<span className="text-xl font-bold">جنسیت</span>
|
||||
<div className="mt-5">
|
||||
<AuthUserDetails />
|
||||
</div>
|
||||
|
||||
<div className="w-full max-w-sm flex flex-col items-center">
|
||||
<div className="flex w-full gap-4">
|
||||
<AuthNextButton
|
||||
type="button"
|
||||
@@ -97,26 +102,21 @@ function Gender() {
|
||||
</AuthNextButton>
|
||||
</div>
|
||||
|
||||
{/* Error Message */}
|
||||
{formik.errors.selectedButton && formik.touched.selectedButton && (
|
||||
<div className="text-red-500 mt-2 text-sm">
|
||||
{formik.errors.selectedButton}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</AuthPageContent>
|
||||
|
||||
<AuthNextButton type="submit" className="mt-20" disabled={loading}>
|
||||
{loading ? "در حال ارسال..." : "ثبت و ادامه"}
|
||||
<AuthFormFooter onSkip={() => router.push("/verify/sizes")}>
|
||||
<AuthNextButton type="submit" loading={loading} disabled={loading}>
|
||||
ثبت و ادامه
|
||||
</AuthNextButton>
|
||||
<button
|
||||
className="text-sm text-gray-500 mt-5"
|
||||
onClick={() => router.push("/verify/sizes")}
|
||||
type="button"
|
||||
>
|
||||
<span>رد کن</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</Container>
|
||||
</AuthFormFooter>
|
||||
</form>
|
||||
</AuthPageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
"use client";
|
||||
|
||||
import Container from "@/components/elements/Container";
|
||||
import AuthPageLayout, {
|
||||
AuthFormFooter,
|
||||
AuthPageContent,
|
||||
} from "@/components/auth/AuthPageLayout";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
import { useFormik } from "formik";
|
||||
@@ -118,20 +121,22 @@ function LocationPage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className="p-4 flex flex-col items-center h-screen justify-center address-page ">
|
||||
<span className="text-xl font-bold">لوکیشن</span>
|
||||
<div className="mt-5">
|
||||
<AuthUserDetails />
|
||||
</div>
|
||||
<AuthPageLayout className="address-page">
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
className="flex w-full flex-1 flex-col items-center"
|
||||
>
|
||||
<AuthPageContent>
|
||||
<span className="text-xl font-bold">لوکیشن</span>
|
||||
<div className="mt-5">
|
||||
<AuthUserDetails />
|
||||
</div>
|
||||
|
||||
<small className="font-bold mt-10 mb-4">
|
||||
مشخص کنید در کدام شهر قادر به انجام فعالیت هستید
|
||||
</small>
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
className="w-full max-w-sm flex flex-col items-center"
|
||||
>
|
||||
<small className="font-bold mt-10 mb-4">
|
||||
مشخص کنید در کدام شهر قادر به انجام فعالیت هستید
|
||||
</small>
|
||||
|
||||
<div className="w-full max-w-sm flex flex-col items-center">
|
||||
<SelectBox
|
||||
className={`mt-4 ${
|
||||
formik.touched.stateId && formik.errors.stateId
|
||||
@@ -230,20 +235,16 @@ function LocationPage() {
|
||||
اطلاعات لوکیشن شما برای همه قابل نمایش باشد
|
||||
</span>
|
||||
</label>
|
||||
<AuthNextButton type="submit" className="mt-20" disabled={loading}>
|
||||
{loading ? "در حال ارسال..." : "ثبت و ادامه"}
|
||||
</AuthNextButton>
|
||||
</div>
|
||||
</AuthPageContent>
|
||||
|
||||
<button
|
||||
className="text-sm text-gray-500 mt-5"
|
||||
onClick={() => router.push("/verify/national-cart")}
|
||||
type="button"
|
||||
>
|
||||
<span>رد کن</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</Container>
|
||||
<AuthFormFooter onSkip={() => router.push("/verify/national-cart")}>
|
||||
<AuthNextButton type="submit" loading={loading} disabled={loading}>
|
||||
ثبت و ادامه
|
||||
</AuthNextButton>
|
||||
</AuthFormFooter>
|
||||
</form>
|
||||
</AuthPageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
"use client";
|
||||
|
||||
import Container from "@/components/elements/Container";
|
||||
import AuthPageLayout, {
|
||||
AuthFormFooter,
|
||||
AuthPageContent,
|
||||
} from "@/components/auth/AuthPageLayout";
|
||||
import React, { useState } from "react";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
import { useRouter } from "next/navigation";
|
||||
@@ -69,8 +72,8 @@ function NationalCart() {
|
||||
};
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className="p-4 flex flex-col items-center h-screen justify-center address-page">
|
||||
<AuthPageLayout className="address-page">
|
||||
<AuthPageContent>
|
||||
<span className="text-xl font-bold">احراز هویت</span>
|
||||
<div className="mt-5">
|
||||
<AuthUserDetails />
|
||||
@@ -146,25 +149,19 @@ function NationalCart() {
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<AuthRules isModalOpen={isModalOpen} setModalOpen={setModalOpen} />
|
||||
</AuthPageContent>
|
||||
|
||||
<AuthFormFooter onSkip={() => router.push("/verify/confirm")}>
|
||||
<AuthNextButton
|
||||
onClick={uploadImage}
|
||||
className="mt-20"
|
||||
loading={loading}
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? "در حال ارسال..." : "ثبت و ادامه"}
|
||||
ثبت و ادامه
|
||||
</AuthNextButton>
|
||||
|
||||
<button
|
||||
className="text-sm text-gray-500 mt-5"
|
||||
onClick={() => router.push("/verify/confirm")}
|
||||
type="button"
|
||||
>
|
||||
رد کن
|
||||
</button>
|
||||
|
||||
<AuthRules isModalOpen={isModalOpen} setModalOpen={setModalOpen} />
|
||||
</div>
|
||||
</Container>
|
||||
</AuthFormFooter>
|
||||
</AuthPageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
"use client";
|
||||
|
||||
import Container from "@/components/elements/Container";
|
||||
import AuthPageLayout, {
|
||||
AuthFormFooter,
|
||||
AuthPageContent,
|
||||
} from "@/components/auth/AuthPageLayout";
|
||||
import React from "react";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
import { useFormik } from "formik";
|
||||
@@ -46,18 +49,18 @@ function PublicRelations() {
|
||||
});
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className="p-4 flex flex-col items-center h-screen justify-center">
|
||||
<span className="text-xl font-bold">روابط عمومی</span>
|
||||
<div className="mt-5">
|
||||
<AuthUserDetails />
|
||||
</div>
|
||||
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
className="w-full max-w-sm flex flex-col items-center"
|
||||
>
|
||||
|
||||
<AuthPageLayout>
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
className="flex w-full flex-1 flex-col items-center"
|
||||
>
|
||||
<AuthPageContent>
|
||||
<span className="text-xl font-bold">روابط عمومی</span>
|
||||
<div className="mt-5">
|
||||
<AuthUserDetails />
|
||||
</div>
|
||||
|
||||
<div className="w-full max-w-sm flex flex-col items-center">
|
||||
<small className="font-bold mt-10"> در مورد خودتان چیزی بگویید</small>
|
||||
<textarea
|
||||
name="bio"
|
||||
@@ -85,20 +88,16 @@ function PublicRelations() {
|
||||
{formik.errors.bio}
|
||||
</small>
|
||||
)}
|
||||
</div>
|
||||
</AuthPageContent>
|
||||
|
||||
<AuthNextButton type="submit" className="mt-20" disabled={loading}>
|
||||
{loading ? "در حال ارسال..." : "ثبت و ادامه"}
|
||||
<AuthFormFooter onSkip={() => router.push("/verify/location")}>
|
||||
<AuthNextButton type="submit" loading={loading} disabled={loading}>
|
||||
ثبت و ادامه
|
||||
</AuthNextButton>
|
||||
<button
|
||||
className="text-sm text-gray-500 mt-5"
|
||||
onClick={() => router.push("/verify/location")}
|
||||
type="button"
|
||||
>
|
||||
<span>رد کن</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</Container>
|
||||
</AuthFormFooter>
|
||||
</form>
|
||||
</AuthPageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,10 @@ import { Service } from "@/types/types";
|
||||
import ServiceItem from "@/components/main/Services/ServiceItem";
|
||||
import AddServiceModal from "@/components/main/Services/AddServiceModal";
|
||||
import AuthUserDetails from "@/components/auth/AuthUserDetails";
|
||||
import Container from "@/components/elements/Container";
|
||||
import AuthPageLayout, {
|
||||
AuthFormFooter,
|
||||
AuthPageContent,
|
||||
} from "@/components/auth/AuthPageLayout";
|
||||
import AuthNextButton from "@/components/auth/AuthNextButton";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
import toast from "react-hot-toast";
|
||||
@@ -80,8 +83,8 @@ const ServicesPage: React.FC = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className="p-4 flex flex-col items-center h-screen justify-center w-full">
|
||||
<AuthPageLayout>
|
||||
<AuthPageContent className="w-full">
|
||||
<span className="text-xl font-bold">خدمات</span>
|
||||
|
||||
<div className="mt-5 w-full max-w-md">
|
||||
@@ -98,23 +101,6 @@ const ServicesPage: React.FC = () => {
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="flex gap-4 mt-6">
|
||||
<AuthNextButton
|
||||
onClick={handleSubmit}
|
||||
disabled={loading}
|
||||
className="mb-4 w-32"
|
||||
>
|
||||
{loading ? "در حال ارسال..." : "ثبت و ادامه"}
|
||||
</AuthNextButton>
|
||||
|
||||
<AuthNextButton
|
||||
onClick={() => setModalOpen(true)}
|
||||
className="mb-4 !text-[#0066FF] !border-[#0066FF] w-32"
|
||||
>
|
||||
افزودن
|
||||
</AuthNextButton>
|
||||
</div>
|
||||
|
||||
{isModalOpen && (
|
||||
<AddServiceModal
|
||||
onClose={() => setModalOpen(false)}
|
||||
@@ -122,15 +108,28 @@ const ServicesPage: React.FC = () => {
|
||||
isModalOpen={isModalOpen}
|
||||
/>
|
||||
)}
|
||||
<button
|
||||
className="text-sm text-gray-500 mt-5"
|
||||
onClick={Reject}
|
||||
type="button"
|
||||
>
|
||||
<span>رد کن</span>
|
||||
</button>
|
||||
</div>
|
||||
</Container>
|
||||
</AuthPageContent>
|
||||
|
||||
<AuthFormFooter onSkip={Reject}>
|
||||
<div className="flex gap-4">
|
||||
<AuthNextButton
|
||||
onClick={handleSubmit}
|
||||
loading={loading}
|
||||
disabled={loading}
|
||||
className="w-32"
|
||||
>
|
||||
ثبت و ادامه
|
||||
</AuthNextButton>
|
||||
|
||||
<AuthNextButton
|
||||
onClick={() => setModalOpen(true)}
|
||||
className="!text-[#0066FF] !border-[#0066FF] w-32"
|
||||
>
|
||||
افزودن
|
||||
</AuthNextButton>
|
||||
</div>
|
||||
</AuthFormFooter>
|
||||
</AuthPageLayout>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
"use client";
|
||||
|
||||
import Container from "@/components/elements/Container";
|
||||
import AuthPageLayout, {
|
||||
AuthFormFooter,
|
||||
AuthPageContent,
|
||||
} from "@/components/auth/AuthPageLayout";
|
||||
import React, { useState } from "react";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
import * as yup from "yup";
|
||||
@@ -73,8 +76,8 @@ function Sizes() {
|
||||
};
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className="p-4 flex flex-col items-center h-screen justify-center">
|
||||
<AuthPageLayout>
|
||||
<AuthPageContent>
|
||||
<span className="text-xl font-bold">سایز</span>
|
||||
<div className="mt-5">
|
||||
<AuthUserDetails />
|
||||
@@ -175,24 +178,19 @@ function Sizes() {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</AuthPageContent>
|
||||
|
||||
<AuthFormFooter onSkip={() => router.push("/verify/colors")}>
|
||||
<AuthNextButton
|
||||
type="button"
|
||||
onClick={handleCheck}
|
||||
className="mt-10"
|
||||
loading={loading}
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? "در حال ارسال..." : "ثبت و ادامه"}
|
||||
ثبت و ادامه
|
||||
</AuthNextButton>
|
||||
<button
|
||||
className="text-sm text-gray-500 mt-5"
|
||||
onClick={() => router.push("/verify/colors")}
|
||||
type="button"
|
||||
>
|
||||
<span>رد کن</span>
|
||||
</button>
|
||||
</div>
|
||||
</Container>
|
||||
</AuthFormFooter>
|
||||
</AuthPageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -502,7 +502,7 @@ select {
|
||||
filter: invert(1) hue-rotate(180deg) brightness(1.2);
|
||||
}
|
||||
|
||||
/* حذف پسزمینه سفید اضافی در برخی مرورگرها */
|
||||
.custom-audio-player::-webkit-media-controls-panel {
|
||||
background-color: transparent;
|
||||
}
|
||||
.profile-avatar {
|
||||
aspect-ratio: 1 / 1;
|
||||
object-fit: cover;
|
||||
}
|
||||
@@ -149,9 +149,9 @@ function NationalCart() {
|
||||
<AuthNextButton
|
||||
onClick={uploadImage}
|
||||
className="mt-20"
|
||||
disabled={loading}
|
||||
loading={loading} disabled={loading}
|
||||
>
|
||||
{loading ? "در حال ارسال..." : "ثبت و ادامه"}
|
||||
ثبت و ادامه
|
||||
</AuthNextButton>
|
||||
|
||||
<button
|
||||
|
||||
@@ -6,6 +6,7 @@ import React, { useState, useEffect } from "react";
|
||||
|
||||
import AuthNextButton from "@/components/auth/AuthNextButton";
|
||||
import Image from "next/image";
|
||||
import ProfileAvatar from "@/components/main/ProfileAvatar";
|
||||
import { useUser } from "@/hooks/useUser";
|
||||
import { BASE_URL, IMAGE_BASE_URL, buildStorageUrl } from "@/components/main/BaseUrl";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
@@ -178,17 +179,13 @@ function LicensePage() {
|
||||
<span className="text-xl mb-9 font-bold">بارگذاری مجوز</span>
|
||||
|
||||
<div className="flex flex-col justify-center items-center">
|
||||
<Image
|
||||
className="rounded-2xl object-cover"
|
||||
width={130}
|
||||
height={130}
|
||||
<ProfileAvatar
|
||||
src={user?.profile_image}
|
||||
alt={user?.user_name || "user profile"}
|
||||
src={
|
||||
user?.profile_image
|
||||
? buildStorageUrl(user.profile_image)
|
||||
: "/images/placeholder.png"
|
||||
}
|
||||
unoptimized={true}
|
||||
size="md"
|
||||
rounded="2xl"
|
||||
className="h-[130px] w-[130px]"
|
||||
fallback="/images/placeholder.png"
|
||||
/>
|
||||
<div className="flex flex-col justify-center items-center gap-1 mt-1">
|
||||
<span>
|
||||
@@ -286,7 +283,7 @@ function LicensePage() {
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<AuthNextButton onClick={upload} className="mt-20">
|
||||
<AuthNextButton onClick={upload} className="mt-20" loading={loadingUpload} disabled={loadingUpload}>
|
||||
ثبت و ادامه
|
||||
</AuthNextButton>
|
||||
<small className="font-bold mt-10 mb-1 text-center">
|
||||
|
||||
@@ -58,7 +58,6 @@ function AvatarPage() {
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
});
|
||||
setLoadingUpload(false);
|
||||
router.push("/settings/edit");
|
||||
} else {
|
||||
setLoadingUpload(false);
|
||||
@@ -80,13 +79,9 @@ function AvatarPage() {
|
||||
return (
|
||||
<Container>
|
||||
<div className="p-4 flex flex-col items-center h-screen justify-center">
|
||||
{loading || loadingUpload ? (
|
||||
<p>Loading...</p>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex flex-col items-center mb-4">
|
||||
<span className="text-xl font-bold">تصویر پروفایل</span>
|
||||
<div className="relative w-[250px] h-[250px] flex items-center justify-center text-white rounded-3xl border border-[#676767] overflow-hidden mt-10">
|
||||
<div className="flex flex-col items-center mb-4">
|
||||
<span className="text-xl font-bold">تصویر پروفایل</span>
|
||||
<div className="relative aspect-square w-[250px] flex items-center justify-center text-white rounded-3xl border border-[#676767] overflow-hidden mt-10">
|
||||
{avatar ? (
|
||||
<>
|
||||
<img
|
||||
@@ -96,7 +91,7 @@ function AvatarPage() {
|
||||
: IMAGE_BASE_URL + avatar
|
||||
}
|
||||
alt="Avatar"
|
||||
className="w-full h-full object-cover"
|
||||
className="w-full h-full aspect-square object-cover"
|
||||
/>
|
||||
<button
|
||||
onClick={removeImage}
|
||||
@@ -141,15 +136,14 @@ function AvatarPage() {
|
||||
</label>
|
||||
</AuthNextButton>
|
||||
|
||||
<AuthNextButton
|
||||
onClick={uploadImage}
|
||||
className="mt-20"
|
||||
disabled={loading}
|
||||
>
|
||||
ویرایش
|
||||
</AuthNextButton>
|
||||
</>
|
||||
)}
|
||||
<AuthNextButton
|
||||
onClick={uploadImage}
|
||||
className="mt-20"
|
||||
loading={loadingUpload}
|
||||
disabled={loadingUpload || loading}
|
||||
>
|
||||
ویرایش
|
||||
</AuthNextButton>
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
|
||||
@@ -75,8 +75,8 @@ function PublicRelations() {
|
||||
</small>
|
||||
)}
|
||||
|
||||
<AuthNextButton type="submit" className="mt-20" disabled={loading}>
|
||||
{loading ? "در حال ارسال..." : "ویرایش"}
|
||||
<AuthNextButton type="submit" className="mt-20" loading={loading} disabled={loading}>
|
||||
ویرایش
|
||||
</AuthNextButton>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -159,9 +159,9 @@ function Colors() {
|
||||
type="button"
|
||||
onClick={handleCheck}
|
||||
className="mt-10"
|
||||
disabled={loading}
|
||||
loading={loading} disabled={loading}
|
||||
>
|
||||
{loading ? "در حال ارسال..." : "ویرایش"}
|
||||
ویرایش
|
||||
</AuthNextButton>
|
||||
</div>
|
||||
</Container>
|
||||
|
||||
@@ -89,8 +89,8 @@ function CooperationType() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
<AuthNextButton type="submit" className="mt-20" disabled={loading}>
|
||||
{loading ? "در حال ارسال..." : "ویرایش"}
|
||||
<AuthNextButton type="submit" className="mt-20" loading={loading} disabled={loading}>
|
||||
ویرایش
|
||||
</AuthNextButton>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -134,9 +134,9 @@ function Expertise() {
|
||||
type="button"
|
||||
onClick={handleCheck}
|
||||
className="mt-20"
|
||||
disabled={loading}
|
||||
loading={loading} disabled={loading}
|
||||
>
|
||||
{loading ? "در حال ارسال..." : "ویرایش"}
|
||||
ویرایش
|
||||
</AuthNextButton>
|
||||
</div>
|
||||
</Container>
|
||||
|
||||
@@ -259,8 +259,8 @@ function LocationPage() {
|
||||
اطلاعات لوکیشن شما برای همه قابل نمایش باشد
|
||||
</span>
|
||||
</label>
|
||||
<AuthNextButton type="submit" className="mt-20" disabled={loading}>
|
||||
{loading ? "در حال ارسال..." : "ویرایش"}
|
||||
<AuthNextButton type="submit" className="mt-20" loading={loading} disabled={loading}>
|
||||
ویرایش
|
||||
</AuthNextButton>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -67,7 +67,8 @@ function PasswordPage() {
|
||||
<AuthPasswordInput
|
||||
name="password"
|
||||
placeholder="کلمه عبور"
|
||||
className={`border mt-4 ${
|
||||
wrapperClassName="mt-4"
|
||||
className={`border ${
|
||||
formik.touched.password && formik.errors.password
|
||||
? "border-red-500 dark:border-red-500"
|
||||
: "border-gray-300"
|
||||
@@ -85,7 +86,8 @@ function PasswordPage() {
|
||||
<AuthPasswordInput
|
||||
name="confirmPassword"
|
||||
placeholder="تکرار کلمه عبور"
|
||||
className={`border mt-4 ${
|
||||
wrapperClassName="mt-4"
|
||||
className={`border ${
|
||||
formik.touched.confirmPassword && formik.errors.confirmPassword
|
||||
? "border-red-500 dark:border-red-500"
|
||||
: "border-gray-300"
|
||||
@@ -100,8 +102,8 @@ function PasswordPage() {
|
||||
</small>
|
||||
)}
|
||||
|
||||
<AuthNextButton type="submit" className="mt-20" disabled={loading}>
|
||||
{loading ? "در حال ارسال..." : "تایید کلمه عبور"}
|
||||
<AuthNextButton type="submit" className="mt-20" loading={loading} disabled={loading}>
|
||||
تایید کلمه عبور
|
||||
</AuthNextButton>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -123,8 +123,8 @@ function PublicRelations() {
|
||||
</small>
|
||||
)}
|
||||
|
||||
<AuthNextButton type="submit" className="mt-20" disabled={loading}>
|
||||
{loading ? "در حال ارسال..." : "ویرایش"}
|
||||
<AuthNextButton type="submit" className="mt-20" loading={loading} disabled={loading}>
|
||||
ویرایش
|
||||
</AuthNextButton>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,7 @@ import React, { useEffect, useState } from "react";
|
||||
import { Service, User } from "@/types/types";
|
||||
import ServiceItem from "@/components/main/Services/ServiceItem";
|
||||
import AddServiceModal from "@/components/main/Services/AddServiceModal";
|
||||
import AuthUserDetails from "@/components/auth/AuthUserDetails";
|
||||
import Container from "@/components/elements/Container";
|
||||
import AuthNextButton from "@/components/auth/AuthNextButton";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
@@ -93,6 +94,10 @@ const ServicesPage: React.FC = () => {
|
||||
<div className="p-4 flex flex-col items-center h-screen justify-center">
|
||||
<span className="text-xl font-bold">خدمات</span>
|
||||
|
||||
<div className="mt-5 w-full max-w-md">
|
||||
<AuthUserDetails />
|
||||
</div>
|
||||
|
||||
<div className="gap-4 min-h-96">
|
||||
{services.map((service) => (
|
||||
<ServiceItem
|
||||
@@ -107,10 +112,10 @@ const ServicesPage: React.FC = () => {
|
||||
<div className="flex gap-4">
|
||||
<AuthNextButton
|
||||
onClick={handleSubmit}
|
||||
disabled={loading}
|
||||
loading={loading} disabled={loading}
|
||||
className="mb-4 w-32"
|
||||
>
|
||||
{loading ? "در حال ارسال..." : "ویرایش"}
|
||||
ویرایش
|
||||
</AuthNextButton>
|
||||
<AuthNextButton
|
||||
onClick={() => setModalOpen(true)}
|
||||
|
||||
@@ -87,8 +87,8 @@ function AuthPage() {
|
||||
<small className="font-bold mt-10">
|
||||
شماره شبا باید به نام خود شخص باشد
|
||||
</small>
|
||||
<AuthNextButton type="submit" className="mt-20" disabled={loading}>
|
||||
{loading ? "در حال ارسال..." : "ویرایش"}
|
||||
<AuthNextButton type="submit" className="mt-20" loading={loading} disabled={loading}>
|
||||
ویرایش
|
||||
</AuthNextButton>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -175,9 +175,9 @@ function Sizes() {
|
||||
type="button"
|
||||
onClick={handleCheck}
|
||||
className="mt-10"
|
||||
disabled={loading}
|
||||
loading={loading} disabled={loading}
|
||||
>
|
||||
{loading ? "در حال ارسال..." : "ویرایش"}
|
||||
ویرایش
|
||||
</AuthNextButton>
|
||||
</div>
|
||||
</Container>
|
||||
|
||||
@@ -11,13 +11,13 @@ import AuthNextButton from "@/components/auth/AuthNextButton";
|
||||
import Container from "@/components/elements/Container";
|
||||
import UsernameSuggestions from "@/components/auth/UsernameSuggestions";
|
||||
import { usernameFormSchema } from "@/lib/validation/usernameSchema";
|
||||
import { sanitizeUsernameInput } from "@/lib/validation/username";
|
||||
import { sanitizeUsernameInput, USERNAME_MIN_LENGTH } from "@/lib/validation/username";
|
||||
|
||||
function UsernamePage() {
|
||||
const router = useRouter();
|
||||
const user = useUser();
|
||||
const { request, loading } = useAxios();
|
||||
const [duplicateError, setDuplicateError] = useState<string | null>(null);
|
||||
const [isDuplicate, setIsDuplicate] = useState(false);
|
||||
const [suggestions, setSuggestions] = useState<string[]>([]);
|
||||
|
||||
const formik = useFormik({
|
||||
@@ -27,7 +27,7 @@ function UsernamePage() {
|
||||
validationSchema: usernameFormSchema,
|
||||
enableReinitialize: true,
|
||||
onSubmit: async (values) => {
|
||||
setDuplicateError(null);
|
||||
setIsDuplicate(false);
|
||||
setSuggestions([]);
|
||||
|
||||
try {
|
||||
@@ -38,16 +38,18 @@ function UsernamePage() {
|
||||
router.push("/settings/edit");
|
||||
} catch (err: any) {
|
||||
const data = err?.response?.data;
|
||||
if (data?.message) {
|
||||
setDuplicateError(data.message);
|
||||
if (data?.message?.includes("تکراری")) {
|
||||
setIsDuplicate(true);
|
||||
setSuggestions(Array.isArray(data.suggestions) ? data.suggestions : []);
|
||||
} else if (data?.message) {
|
||||
formik.setFieldError("username", data.message);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const handleUsernameChange = (value: string) => {
|
||||
setDuplicateError(null);
|
||||
setIsDuplicate(false);
|
||||
setSuggestions([]);
|
||||
formik.setFieldValue("username", sanitizeUsernameInput(value));
|
||||
};
|
||||
@@ -55,7 +57,7 @@ function UsernamePage() {
|
||||
const handleSuggestionSelect = (username: string) => {
|
||||
formik.setFieldValue("username", username);
|
||||
formik.setFieldTouched("username", true, false);
|
||||
setDuplicateError(null);
|
||||
setIsDuplicate(false);
|
||||
setSuggestions([]);
|
||||
};
|
||||
|
||||
@@ -70,12 +72,12 @@ function UsernamePage() {
|
||||
<AuthInput
|
||||
name="username"
|
||||
type="text"
|
||||
placeholder="example_user"
|
||||
placeholder="نام کاربری"
|
||||
dir="ltr"
|
||||
autoComplete="username"
|
||||
spellCheck={false}
|
||||
className={`border ${
|
||||
(formik.touched.username && formik.errors.username) || duplicateError
|
||||
(formik.touched.username && formik.errors.username) || isDuplicate
|
||||
? "border-red-500 dark:border-red-500"
|
||||
: "border-gray-300"
|
||||
}`}
|
||||
@@ -83,25 +85,30 @@ function UsernamePage() {
|
||||
onChange={(e) => handleUsernameChange(e.target.value)}
|
||||
onBlur={formik.handleBlur}
|
||||
/>
|
||||
<small className="text-gray-500 dark:text-gray-400 text-xs mt-2 text-center leading-5">
|
||||
فقط حروف انگلیسی، اعداد و کاراکترهای . _ - (حداقل ۶ کاراکتر)
|
||||
</small>
|
||||
{formik.touched.username && formik.errors.username && !duplicateError && (
|
||||
<small className="text-red-500 mt-2 block">
|
||||
|
||||
{isDuplicate && (
|
||||
<small className="text-red-500 mt-2 block text-center font-medium">
|
||||
نام کاربری تکراری است
|
||||
</small>
|
||||
)}
|
||||
|
||||
{formik.touched.username && formik.errors.username && !isDuplicate && (
|
||||
<small className="text-red-500 mt-2 block text-center">
|
||||
{formik.errors.username}
|
||||
</small>
|
||||
)}
|
||||
|
||||
<UsernameSuggestions
|
||||
message={duplicateError || undefined}
|
||||
suggestions={suggestions}
|
||||
onSelect={handleSuggestionSelect}
|
||||
/>
|
||||
|
||||
<AuthNextButton
|
||||
type="submit"
|
||||
className="mt-20"
|
||||
disabled={loading || formik.values.username.length < 6}
|
||||
loading={loading} disabled={loading || formik.values.username.length < USERNAME_MIN_LENGTH}
|
||||
>
|
||||
{loading ? "در حال ارسال..." : "ویرایش"}
|
||||
ویرایش
|
||||
</AuthNextButton>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
"use client"
|
||||
import { IMAGE_BASE_URL, buildStorageUrl } from "@/components/main/BaseUrl";
|
||||
import ProfileAvatar from "@/components/main/ProfileAvatar";
|
||||
import { User } from "@/types/types";
|
||||
import Image from "next/image";
|
||||
import React, { useState } from "react";
|
||||
import ModelHeadRowTwo from "../models/ModelPage/ModelHeadRowTwo";
|
||||
import ModelHeadRowThree from "../models/ModelPage/ModelHeadRowThree";
|
||||
@@ -108,25 +106,13 @@ function ModelHead({ user, item2 }: ModelHeadProps) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{profile_image ? (
|
||||
<Image
|
||||
className="rounded-xl object-cover h-[72px] w-[72px] md:h-[120px] md:w-[120px]"
|
||||
width={120}
|
||||
height={120}
|
||||
alt={user_name}
|
||||
src={buildStorageUrl(profile_image)}
|
||||
unoptimized={true}
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
className="rounded-xl object-cover h-[72px] w-[72px] md:h-[120px] md:w-[120px]"
|
||||
width={120}
|
||||
height={120}
|
||||
alt={user_name}
|
||||
src={`/images/fake-avatar.png`}
|
||||
unoptimized={true}
|
||||
/>
|
||||
)}
|
||||
<ProfileAvatar
|
||||
src={profile_image}
|
||||
alt={user_name}
|
||||
size="md"
|
||||
rounded="xl"
|
||||
className="md:h-[120px] md:w-[120px]"
|
||||
/>
|
||||
</div>
|
||||
<ModelHeadRowTwo
|
||||
first_name={first_name}
|
||||
|
||||
@@ -1,13 +1,42 @@
|
||||
import React, { ComponentProps } from "react";
|
||||
type TButton = ComponentProps<"button"> & {};
|
||||
function AuthButton({ children, style, className, ...rest }: TButton) {
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type TButton = ComponentProps<"button"> & {
|
||||
loading?: boolean;
|
||||
loadingText?: string;
|
||||
};
|
||||
|
||||
function AuthButton({
|
||||
children,
|
||||
style,
|
||||
className,
|
||||
loading = false,
|
||||
loadingText = "در حال ارسال...",
|
||||
disabled,
|
||||
...rest
|
||||
}: TButton) {
|
||||
return (
|
||||
<button
|
||||
className={`w-full dir-ltr max-w-[290px] p-3 text-center text-white rounded-2xl bg-[#FC8EAC] hover:bg-[#f85e87] font-bold duration-300 ${className}`}
|
||||
style={{ ...style }}
|
||||
className={cn(
|
||||
"w-full dir-ltr max-w-[290px] p-3 text-center text-white rounded-2xl bg-[#FC8EAC] hover:bg-[#f85e87] font-bold duration-300",
|
||||
loading && "cursor-wait opacity-80",
|
||||
className
|
||||
)}
|
||||
style={style}
|
||||
disabled={disabled || loading}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
{loading ? (
|
||||
<span className="inline-flex items-center justify-center gap-2">
|
||||
<span
|
||||
className="h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent"
|
||||
aria-hidden
|
||||
/>
|
||||
<span>{loadingText}</span>
|
||||
</span>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ function AuthInput({ style, className, ...rest }: TInput) {
|
||||
return (
|
||||
<input
|
||||
className={cn(
|
||||
"w-full dir-ltr max-w-[290px] p-3.5 text-center text-lg font-semibold rounded-2xl",
|
||||
"w-full max-w-[290px] p-3.5 text-center text-lg font-semibold rounded-2xl",
|
||||
"border-2 border-gray-200 dark:border-gray-300",
|
||||
"bg-white text-gray-900 placeholder:text-gray-400",
|
||||
"dark:bg-white dark:text-gray-900 dark:placeholder:text-gray-500",
|
||||
|
||||
@@ -1,13 +1,42 @@
|
||||
import React, { ComponentProps } from "react";
|
||||
type TButton = ComponentProps<"button"> & {};
|
||||
function AuthNextButton({ children, style, className, ...rest }: TButton) {
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type TButton = ComponentProps<"button"> & {
|
||||
loading?: boolean;
|
||||
loadingText?: string;
|
||||
};
|
||||
|
||||
function AuthNextButton({
|
||||
children,
|
||||
style,
|
||||
className,
|
||||
loading = false,
|
||||
loadingText = "در حال ارسال...",
|
||||
disabled,
|
||||
...rest
|
||||
}: TButton) {
|
||||
return (
|
||||
<button
|
||||
className={`border dir-ltr p-7 py-2 text-center text-border-secondary-light dark:text-border-secondary-dark border-border-secondary-light dark:border-border-secondary-dark rounded-3xl bg-tertiary-light dark:bg-tertiary-dark font-medium duration-300 hover:opacity-70 text-sm ${className}`}
|
||||
style={{ ...style }}
|
||||
className={cn(
|
||||
"border dir-ltr p-7 py-2 text-center text-border-secondary-light dark:text-border-secondary-dark border-border-secondary-light dark:border-border-secondary-dark rounded-3xl bg-tertiary-light dark:bg-tertiary-dark font-medium duration-300 hover:opacity-70 text-sm",
|
||||
loading && "cursor-wait opacity-70",
|
||||
className
|
||||
)}
|
||||
style={style}
|
||||
disabled={disabled || loading}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
{loading ? (
|
||||
<span className="inline-flex items-center justify-center gap-2">
|
||||
<span
|
||||
className="h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent"
|
||||
aria-hidden
|
||||
/>
|
||||
<span>{loadingText}</span>
|
||||
</span>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
79
src/components/auth/AuthPageLayout.tsx
Normal file
79
src/components/auth/AuthPageLayout.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import React from "react";
|
||||
import Container from "@/components/elements/Container";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type AuthPageLayoutProps = {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export function AuthPageContent({
|
||||
children,
|
||||
className,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"flex w-full flex-1 flex-col items-center justify-center",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
type AuthFormFooterProps = {
|
||||
children: React.ReactNode;
|
||||
onSkip?: () => void;
|
||||
skipDisabled?: boolean;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export function AuthFormFooter({
|
||||
children,
|
||||
onSkip,
|
||||
skipDisabled,
|
||||
className,
|
||||
}: AuthFormFooterProps) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"mt-auto flex w-full flex-col items-center gap-3 pt-6 pb-[max(2rem,env(safe-area-inset-bottom))]",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
{onSkip && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onSkip}
|
||||
disabled={skipDisabled}
|
||||
className="text-sm text-gray-500 disabled:opacity-50"
|
||||
>
|
||||
رد کن
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function AuthPageLayout({ children, className }: AuthPageLayoutProps) {
|
||||
return (
|
||||
<Container>
|
||||
<div
|
||||
className={cn(
|
||||
"flex min-h-screen flex-col items-center p-4",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export default AuthPageLayout;
|
||||
@@ -1,7 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import React, { ComponentProps, useState } from "react";
|
||||
import Image from "next/image";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type AuthPasswordInputProps = Omit<ComponentProps<"input">, "type"> & {
|
||||
@@ -35,16 +34,18 @@ function AuthPasswordInput({
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setVisible((prev) => !prev)}
|
||||
className="absolute right-3 top-1/2 -translate-y-1/2 p-1 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-200 transition-colors"
|
||||
className="absolute right-3 top-1/2 -translate-y-1/2 m-0 flex size-[22px] items-center justify-center rounded p-0 hover:opacity-70 transition-opacity"
|
||||
aria-label={visible ? "مخفی کردن کلمه عبور" : "نمایش کلمه عبور"}
|
||||
tabIndex={-1}
|
||||
>
|
||||
<Image
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src={visible ? "/images/icons/eye-slash.png" : "/images/icons/eye-open.png"}
|
||||
alt=""
|
||||
width={22}
|
||||
height={22}
|
||||
className="opacity-80"
|
||||
className="block size-[22px] object-contain object-center opacity-80"
|
||||
draggable={false}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"use client";
|
||||
import ProfileAvatar from "@/components/main/ProfileAvatar";
|
||||
import useAxios from "@/hooks/useAxios";
|
||||
import { IProfileData } from "@/types/types";
|
||||
import React, { useEffect, useState } from "react";
|
||||
@@ -6,7 +7,7 @@ import React, { useEffect, useState } from "react";
|
||||
function AuthUserDetails() {
|
||||
const [userDetail, setUserDetail] = useState<IProfileData | null>(null);
|
||||
const { request } = useAxios();
|
||||
// Fetch user data
|
||||
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const response = await request<{ user: IProfileData }>("GET", "/profile");
|
||||
@@ -15,17 +16,25 @@ function AuthUserDetails() {
|
||||
console.log(err);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mt-5 flex w-full max-w-md flex-col items-center text-center">
|
||||
<ProfileAvatar
|
||||
src={userDetail?.profile_image}
|
||||
alt={userDetail?.user_name || "profile"}
|
||||
size="md"
|
||||
rounded="xl"
|
||||
className="mb-3"
|
||||
/>
|
||||
<span className="text-lg font-bold">
|
||||
{userDetail?.first_name} {userDetail?.last_name}
|
||||
</span>
|
||||
<p className="text-sm text-gray-500">{userDetail?.user_name}</p>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,48 +1,30 @@
|
||||
"use client";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import React from "react";
|
||||
|
||||
interface UsernameSuggestionsProps {
|
||||
message?: string;
|
||||
suggestions?: string[];
|
||||
suggestions: string[];
|
||||
onSelect: (username: string) => void;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default function UsernameSuggestions({
|
||||
message,
|
||||
suggestions = [],
|
||||
suggestions,
|
||||
onSelect,
|
||||
className,
|
||||
}: UsernameSuggestionsProps) {
|
||||
if (!message && suggestions.length === 0) return null;
|
||||
if (!suggestions.length) return null;
|
||||
|
||||
return (
|
||||
<div className={cn("w-full max-w-sm mt-3 space-y-3", className)}>
|
||||
{message && (
|
||||
<p className="text-red-500 text-sm text-center font-medium">{message}</p>
|
||||
)}
|
||||
|
||||
{suggestions.length > 0 && (
|
||||
<div className="space-y-2">
|
||||
<p className="text-xs text-gray-600 dark:text-gray-300 text-center">
|
||||
پیشنهادهای در دسترس:
|
||||
</p>
|
||||
<div className="flex flex-wrap justify-center gap-2">
|
||||
{suggestions.map((item) => (
|
||||
<button
|
||||
key={item}
|
||||
type="button"
|
||||
onClick={() => onSelect(item)}
|
||||
dir="ltr"
|
||||
className="px-3 py-2 rounded-xl border-2 border-[#387E65]/40 bg-white dark:bg-white text-[#387E65] text-sm font-semibold hover:bg-[#387E65]/10 hover:border-[#387E65] transition-colors"
|
||||
>
|
||||
{item}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-wrap justify-center gap-2 mt-3 w-full max-w-[290px]">
|
||||
{suggestions.map((username) => (
|
||||
<button
|
||||
key={username}
|
||||
type="button"
|
||||
onClick={() => onSelect(username)}
|
||||
className="px-3 py-1.5 text-sm font-medium rounded-full border border-[#387E65] text-[#387E65] bg-white hover:bg-[#387E65]/10 transition-colors dir-ltr"
|
||||
>
|
||||
{username}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
"use client"
|
||||
import { IMAGE_BASE_URL, buildStorageUrl } from "@/components/main/BaseUrl";
|
||||
import ProfileAvatar from "@/components/main/ProfileAvatar";
|
||||
import { IAdvertisingProfile } from "@/types/types";
|
||||
import Image from "next/image";
|
||||
import React, { useState } from "react";
|
||||
@@ -40,13 +39,12 @@ function AdProfileHead({ profile, id }: AdProfileHeadProps) {
|
||||
</div>
|
||||
</div>
|
||||
{profile_image ? (
|
||||
<Image
|
||||
className="rounded-xl object-cover h-[72px] w-[72px] md:h-[120px] md:w-[120px]"
|
||||
width={120}
|
||||
height={120}
|
||||
<ProfileAvatar
|
||||
src={profile_image}
|
||||
alt={profile?.vitrine_name || "Name"}
|
||||
src={buildStorageUrl(profile_image)}
|
||||
unoptimized={true}
|
||||
size="md"
|
||||
rounded="xl"
|
||||
className="md:h-[120px] md:w-[120px]"
|
||||
/>
|
||||
) : (
|
||||
<div className="border dark:border-border-primary-dark rounded-3xl p-2">
|
||||
@@ -92,13 +90,12 @@ function AdProfileHead({ profile, id }: AdProfileHeadProps) {
|
||||
</div>
|
||||
</div>
|
||||
{profile_image ? (
|
||||
<Image
|
||||
className="rounded-xl object-cover h-[72px] w-[72px] md:h-[120px] md:w-[120px]"
|
||||
width={120}
|
||||
height={120}
|
||||
<ProfileAvatar
|
||||
src={profile_image}
|
||||
alt={profile?.vitrine_name || "Name"}
|
||||
src={buildStorageUrl(profile_image)}
|
||||
unoptimized={true}
|
||||
size="md"
|
||||
rounded="xl"
|
||||
className="md:h-[120px] md:w-[120px]"
|
||||
/>
|
||||
) : (
|
||||
<div className="border dark:border-border-primary-dark rounded-3xl p-2">
|
||||
|
||||
@@ -5,7 +5,7 @@ import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
import { FiChevronRight } from "react-icons/fi";
|
||||
import { IMAGE_BASE_URL, buildStorageUrl } from "../main/BaseUrl";
|
||||
import ProfileAvatar from "../main/ProfileAvatar";
|
||||
import { useRouter } from "next/navigation";
|
||||
import ChatHeaderMenu from "./ChatHeaderMenu";
|
||||
|
||||
@@ -42,12 +42,11 @@ function ChatHeader({
|
||||
className="gentle-transition flex min-w-0 flex-1 items-center gap-2 active:opacity-80"
|
||||
>
|
||||
{user?.profile_image && !user?.blocked_you ? (
|
||||
<Image
|
||||
width={40}
|
||||
height={40}
|
||||
alt=""
|
||||
src={buildStorageUrl(user.profile_image)}
|
||||
className="h-10 w-10 shrink-0 rounded-full object-cover"
|
||||
<ProfileAvatar
|
||||
src={user.profile_image}
|
||||
alt={user.user_name || ""}
|
||||
size="sm"
|
||||
rounded="full"
|
||||
/>
|
||||
) : (
|
||||
<div className="h-10 w-10 shrink-0 rounded-full bg-neutral-200 dark:bg-neutral-700" />
|
||||
|
||||
56
src/components/main/ProfileAvatar.tsx
Normal file
56
src/components/main/ProfileAvatar.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
import Image from "next/image";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { buildStorageUrl } from "./BaseUrl";
|
||||
|
||||
const sizeMap = {
|
||||
xs: "h-8 w-8",
|
||||
sm: "h-10 w-10",
|
||||
md: "h-[72px] w-[72px]",
|
||||
lg: "h-[120px] w-[120px]",
|
||||
xl: "h-[280px] w-[280px]",
|
||||
};
|
||||
|
||||
type ProfileAvatarProps = {
|
||||
src?: string | null;
|
||||
alt?: string;
|
||||
size?: keyof typeof sizeMap;
|
||||
rounded?: "2xl" | "xl" | "full";
|
||||
className?: string;
|
||||
fallback?: string;
|
||||
};
|
||||
|
||||
function ProfileAvatar({
|
||||
src,
|
||||
alt = "",
|
||||
size = "md",
|
||||
rounded = "2xl",
|
||||
className,
|
||||
fallback = "/images/fake-avatar.png",
|
||||
}: ProfileAvatarProps) {
|
||||
const roundedClass =
|
||||
rounded === "full"
|
||||
? "rounded-full"
|
||||
: rounded === "xl"
|
||||
? "rounded-xl"
|
||||
: "rounded-2xl";
|
||||
|
||||
const imageSrc = src ? buildStorageUrl(src) : fallback;
|
||||
|
||||
return (
|
||||
<Image
|
||||
src={imageSrc}
|
||||
alt={alt}
|
||||
width={280}
|
||||
height={280}
|
||||
unoptimized
|
||||
className={cn(
|
||||
"profile-avatar aspect-square object-cover shrink-0",
|
||||
sizeMap[size],
|
||||
roundedClass,
|
||||
className
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default ProfileAvatar;
|
||||
@@ -1,7 +1,7 @@
|
||||
import Image from "next/image";
|
||||
import React from "react";
|
||||
import { IMAGE_BASE_URL, buildStorageUrl } from "./BaseUrl";
|
||||
import Link from "next/link";
|
||||
import ProfileAvatar from "./ProfileAvatar";
|
||||
|
||||
interface IUserInfoProps {
|
||||
profile_image: string | null | undefined;
|
||||
@@ -22,50 +22,22 @@ function UserInfo({
|
||||
is_verified,
|
||||
noLink,
|
||||
}: IUserInfoProps) {
|
||||
const avatar = (
|
||||
<ProfileAvatar
|
||||
src={profile_image}
|
||||
alt={user_name || ""}
|
||||
size="md"
|
||||
rounded="2xl"
|
||||
className="ml-3"
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex items-center text-xs max-sm:text-[10px] md:text-sm font-semibold">
|
||||
{noLink ? (
|
||||
profile_image ? (
|
||||
<Image
|
||||
className="rounded-2xl object-cover h-[72px] w-[72px] ml-3"
|
||||
width={75}
|
||||
height={75}
|
||||
alt={user_name || ""}
|
||||
src={buildStorageUrl(profile_image)}
|
||||
unoptimized={true}
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
className="rounded-2xl object-cover h-[72px] w-[72px] ml-3"
|
||||
width={75}
|
||||
height={75}
|
||||
alt={user_name || ""}
|
||||
src={`/images/fake-avatar.png`}
|
||||
unoptimized={true}
|
||||
/>
|
||||
)
|
||||
avatar
|
||||
) : (
|
||||
<Link href={`/users/${user_name}`}>
|
||||
{profile_image ? (
|
||||
<Image
|
||||
className="rounded-2xl object-cover h-[72px] w-[72px] ml-3"
|
||||
width={75}
|
||||
height={75}
|
||||
alt={user_name || ""}
|
||||
src={buildStorageUrl(profile_image)}
|
||||
unoptimized={true}
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
className="rounded-2xl object-cover h-[72px] w-[72px] ml-3"
|
||||
width={75}
|
||||
height={75}
|
||||
alt={user_name || ""}
|
||||
src={`/images/fake-avatar.png`}
|
||||
unoptimized={true}
|
||||
/>
|
||||
)}
|
||||
</Link>
|
||||
<Link href={`/users/${user_name}`}>{avatar}</Link>
|
||||
)}
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="text-[#387E65]">
|
||||
@@ -88,14 +60,16 @@ function UserInfo({
|
||||
alt={"not-verify icon"}
|
||||
src={`/images/icons/not-verify.svg`}
|
||||
/>
|
||||
) :is_verified === "true" ? (
|
||||
) : is_verified === "true" ? (
|
||||
<Image
|
||||
width={22}
|
||||
height={22}
|
||||
alt="verify icon"
|
||||
src="/images/icons/verify2.svg"
|
||||
/>
|
||||
): ("")}
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -120,7 +120,7 @@ function CommentsModal({ isOpen, onClose, userId, postId }: CommentsModalProps)
|
||||
className="mb-4 flex flex-row border-b border-neutral-100 pb-2 dark:border-neutral-800"
|
||||
>
|
||||
<Image
|
||||
className="ml-2 min-h-16 max-h-16 min-w-16 max-w-16 rounded-xl"
|
||||
className="ml-2 aspect-square min-h-16 max-h-16 min-w-16 max-w-16 rounded-xl object-cover"
|
||||
width={50}
|
||||
height={50}
|
||||
alt={item?.user?.user_name}
|
||||
|
||||
@@ -175,7 +175,7 @@ function MainModelCard({ postData }: { postData: Post }) {
|
||||
}
|
||||
alt={user_name}
|
||||
fill
|
||||
className="rounded-xl object-cover"
|
||||
className="rounded-xl object-cover aspect-square"
|
||||
priority
|
||||
unoptimized
|
||||
/>
|
||||
|
||||
@@ -174,7 +174,7 @@ function MainModelCard({ postData }: { postData: Post }) {
|
||||
}
|
||||
alt={user_name}
|
||||
fill
|
||||
className="rounded-xl object-cover"
|
||||
className="rounded-xl object-cover aspect-square"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
"use client"
|
||||
import { IMAGE_BASE_URL, buildStorageUrl } from "@/components/main/BaseUrl";
|
||||
import ProfileAvatar from "@/components/main/ProfileAvatar";
|
||||
import { User } from "@/types/types";
|
||||
import Image from "next/image";
|
||||
import React, { useState } from "react";
|
||||
import ModelHeadRowTwo from "./ModelHeadRowTwo";
|
||||
import ModelHeadRowThree from "./ModelHeadRowThree";
|
||||
@@ -108,25 +106,13 @@ function ModelHead({ user, item2 }: ModelHeadProps) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{profile_image ? (
|
||||
<Image
|
||||
className="rounded-xl object-cover h-[72px] w-[72px] md:h-[120px] md:w-[120px]"
|
||||
width={120}
|
||||
height={120}
|
||||
alt={user_name}
|
||||
src={buildStorageUrl(profile_image)}
|
||||
unoptimized={true}
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
className="rounded-xl object-cover h-[72px] w-[72px] md:h-[120px] md:w-[120px]"
|
||||
width={120}
|
||||
height={120}
|
||||
alt={user_name}
|
||||
src={`/images/fake-avatar.png`}
|
||||
unoptimized={true}
|
||||
/>
|
||||
)}
|
||||
<ProfileAvatar
|
||||
src={profile_image}
|
||||
alt={user_name}
|
||||
size="md"
|
||||
rounded="xl"
|
||||
className="md:h-[120px] md:w-[120px]"
|
||||
/>
|
||||
</div>
|
||||
<ModelHeadRowTwo
|
||||
first_name={first_name}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { IProjectCreator } from "@/types/types";
|
||||
import React from "react";
|
||||
import Image from "next/image";
|
||||
import { IMAGE_BASE_URL, buildStorageUrl } from "@/components/main/BaseUrl";
|
||||
import ProfileAvatar from "@/components/main/ProfileAvatar";
|
||||
import Link from "next/link";
|
||||
|
||||
function ProjectCreator({ creator }: { creator: IProjectCreator }) {
|
||||
@@ -11,13 +11,12 @@ function ProjectCreator({ creator }: { creator: IProjectCreator }) {
|
||||
className="w-full flex items-center my-3"
|
||||
>
|
||||
{creator?.profile_image && (
|
||||
<Image
|
||||
className="rounded-2xl object-cover h-[72px] w-[72px] md:h-[120px] md:w-[120px] ml-2"
|
||||
width={120}
|
||||
height={120}
|
||||
<ProfileAvatar
|
||||
src={creator.profile_image}
|
||||
alt={creator?.user_name}
|
||||
src={buildStorageUrl(creator?.profile_image)}
|
||||
unoptimized={true}
|
||||
size="md"
|
||||
rounded="2xl"
|
||||
className="ml-2 md:h-[120px] md:w-[120px]"
|
||||
/>
|
||||
)}
|
||||
<div className="flex flex-col gap-1">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import Image from "next/image";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { IMAGE_BASE_URL, buildStorageUrl } from "../main/BaseUrl";
|
||||
import ProfileAvatar from "../main/ProfileAvatar";
|
||||
import CompleteRegister from "./settings/CompleteRegister";
|
||||
import Link from "next/link";
|
||||
import { useUser } from "@/hooks/useUser";
|
||||
@@ -10,27 +10,23 @@ import { useUser } from "@/hooks/useUser";
|
||||
function UserDetails() {
|
||||
const [isRegister, setIsRegister] = useState<string | undefined>("false");
|
||||
const user = useUser();
|
||||
|
||||
useEffect(() => {
|
||||
setIsRegister(user?.is_Register);
|
||||
}, [user]);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Link
|
||||
href={"/settings/profile"}
|
||||
className="flex items-center text-xs md:text-sm font-semibold"
|
||||
>
|
||||
<Image
|
||||
className="rounded-2xl object-cover h-[72px] w-[72px] md:h-[120px] md:w-[120px] ml-3"
|
||||
width={120}
|
||||
height={120}
|
||||
<ProfileAvatar
|
||||
src={user?.profile_image}
|
||||
alt={user?.user_name || "user profile"}
|
||||
src={buildStorageUrl(user?.profile_image)}
|
||||
unoptimized={true}
|
||||
size="md"
|
||||
rounded="2xl"
|
||||
className="ml-3 md:h-[120px] md:w-[120px]"
|
||||
/>
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="text-[#387E65]">
|
||||
@@ -43,29 +39,29 @@ function UserDetails() {
|
||||
<div className="flex items-center gap-1 mt-1">
|
||||
{user?.user_name}
|
||||
{isRegister === "verified" ? (
|
||||
<Image
|
||||
width={22}
|
||||
height={22}
|
||||
alt={"verify icon"}
|
||||
src={`/images/icons/verify.svg`}
|
||||
/>
|
||||
) : isRegister === "pending" ? (
|
||||
<Image
|
||||
width={25}
|
||||
height={25}
|
||||
alt={"not-verify icon"}
|
||||
src={`/images/icons/not-verify.svg`}
|
||||
/>
|
||||
) : isRegister === "true" ? (
|
||||
<Image
|
||||
width={22}
|
||||
height={22}
|
||||
alt="verify icon"
|
||||
src="/images/icons/verify2.svg"
|
||||
/>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<Image
|
||||
width={22}
|
||||
height={22}
|
||||
alt={"verify icon"}
|
||||
src={`/images/icons/verify.svg`}
|
||||
/>
|
||||
) : isRegister === "pending" ? (
|
||||
<Image
|
||||
width={25}
|
||||
height={25}
|
||||
alt={"not-verify icon"}
|
||||
src={`/images/icons/not-verify.svg`}
|
||||
/>
|
||||
) : isRegister === "true" ? (
|
||||
<Image
|
||||
width={22}
|
||||
height={22}
|
||||
alt="verify icon"
|
||||
src="/images/icons/verify2.svg"
|
||||
/>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<span className="mr-4">{user?.mobile}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user