Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 64 additions & 8 deletions apps/customer_dashboard/src/app/users/forgot_password/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import {
EMAIL_REGEX,
EMAIL_VERIFICATION_TIMER_SECONDS,
PASSWORD_MIN_LENGTH,
PASSWORD_MAX_LENGTH,
PASSWORD_CONTAINS_NUMBER_REGEX,
SIX_DIGITS_REGEX,
} from "@oko-wallet-ct-dashboard/constants";
import { ExpiryTimer } from "@oko-wallet-ct-dashboard/components/expiry_timer/expiry_timer";
Expand Down Expand Up @@ -49,6 +51,7 @@ export default function ForgotPasswordPage() {

const [showPassword, setShowPassword] = useState(false);
const [showConfirm, setShowConfirm] = useState(false);
const [isCodeExpired, setIsCodeExpired] = useState(false);

const codeValue = useMemo(() => codeDigits.join(""), [codeDigits]);

Expand Down Expand Up @@ -116,13 +119,22 @@ export default function ForgotPasswordPage() {
setError(`Password must be at least ${PASSWORD_MIN_LENGTH} characters`);
return;
}
if (password.length > PASSWORD_MAX_LENGTH) {
setError(`Password must be at most ${PASSWORD_MAX_LENGTH} characters`);
return;
}
if (!PASSWORD_CONTAINS_NUMBER_REGEX.test(password)) {
setError("Password must include at least one number");
return;
}
if (password !== confirmPassword) {
setError("Passwords do not match");
return;
}

setIsLoading(true);
resetError();
setIsCodeExpired(false);
try {
const res = await requestResetPasswordConfirm(
email,
Expand All @@ -132,7 +144,38 @@ export default function ForgotPasswordPage() {
if (res.success) {
router.push(paths.home);
} else {
setError(res.msg || "Failed to reset password");
if (res.code === "INVALID_VERIFICATION_CODE") {
setIsCodeExpired(true);
setError("Verification code has expired. Please request a new code.");
} else {
setError(res.msg || "Failed to reset password");
}
}
} catch (err) {
setError("An unexpected error occurred");
} finally {
setIsLoading(false);
}
};

const handleRequestNewCode = async () => {
if (!email || isLoading) {
return;
}

setIsLoading(true);
resetError();
setIsCodeExpired(false);
try {
const res = await requestForgotPassword(email);
if (res.success) {
setCodeDigits(EMPTY_CODE);
setVerifiedCode("");
setPassword("");
setConfirmPassword("");
goToStep(Step.CODE);
} else {
setError(res.msg || "Failed to send code");
}
} catch (err) {
setError("An unexpected error occurred");
Expand Down Expand Up @@ -317,6 +360,7 @@ export default function ForgotPasswordPage() {
}}
fullWidth
requiredSymbol
maxLength={16}
helpText={
error
? undefined
Expand Down Expand Up @@ -344,6 +388,7 @@ export default function ForgotPasswordPage() {
}}
fullWidth
requiredSymbol
maxLength={16}
SideComponent={
<button
type="button"
Expand Down Expand Up @@ -373,13 +418,24 @@ export default function ForgotPasswordPage() {
)}

<div className={styles.passwordButton}>
<Button
type="submit"
fullWidth
disabled={!password || !confirmPassword || isLoading}
>
{isLoading ? "Updating..." : "Update"}
</Button>
{isCodeExpired ? (
<Button
type="button"
fullWidth
onClick={handleRequestNewCode}
disabled={isLoading}
>
{isLoading ? "Sending..." : "Request New Code"}
</Button>
) : (
<Button
type="submit"
fullWidth
disabled={!password || !confirmPassword || isLoading}
>
{isLoading ? "Updating..." : "Update"}
</Button>
)}
</div>
</form>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { useForm, type SubmitHandler } from "react-hook-form";
import { useRouter } from "next/navigation";

import { paths } from "@oko-wallet-ct-dashboard/paths";
import { PASSWORD_MIN_LENGTH } from "@oko-wallet-ct-dashboard/constants";
import {
PASSWORD_MIN_LENGTH,
PASSWORD_MAX_LENGTH,
PASSWORD_CONTAINS_NUMBER_REGEX,
} from "@oko-wallet-ct-dashboard/constants";
import { requestChangePassword } from "@oko-wallet-ct-dashboard/fetch/users";
import { useAppState } from "@oko-wallet-ct-dashboard/state";

Expand Down Expand Up @@ -91,6 +95,16 @@ function resetPasswordResolver(values: ResetPasswordInputs) {
type: "minLength",
message: `Password must be at least ${PASSWORD_MIN_LENGTH} characters`,
};
} else if (values.newPassword.length > PASSWORD_MAX_LENGTH) {
errors.newPassword = {
type: "maxLength",
message: `Password must be at most ${PASSWORD_MAX_LENGTH} characters`,
};
} else if (!PASSWORD_CONTAINS_NUMBER_REGEX.test(values.newPassword)) {
errors.newPassword = {
type: "pattern",
message: "Password must include at least one number",
};
}

if (!values.confirmPassword) {
Expand Down
4 changes: 3 additions & 1 deletion apps/customer_dashboard/src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
export const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
export const PASSWORD_MIN_LENGTH = 8;
export const PASSWORD_MAX_LENGTH = 16;
export const PASSWORD_CONTAINS_NUMBER_REGEX = /\d/;

export const SIX_DIGITS_REGEX = /^\d{6}$/;

export const EMAIL_VERIFICATION_TIMER_SECONDS = 60 * 3;
export const EMAIL_VERIFICATION_TIMER_SECONDS = 60;

export const GET_STARTED_URL = "https://form.typeform.com/to/MxrBGq9b";
46 changes: 14 additions & 32 deletions apps/docs_web/docs/v0/sdk-usage/cosmos-kit-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,16 @@ npm install @cosmjs/amino @cosmjs/proto-signing

## Basic Setup

### 1. Create Oko Wallets
### 1. Create Oko Wallet

Use `makeOkoWallets` to generate wallet instances for your desired login
providers:
Use `makeOkoWallet` to create a wallet instance:

```typescript
import { makeOkoWallets } from "@oko-wallet/oko-cosmos-kit";
import { makeOkoWallet } from "@oko-wallet/oko-cosmos-kit";

const okoWallets = makeOkoWallets({
const okoWallet = makeOkoWallet({
apiKey: "your-oko-api-key",
sdkEndpoint: "https://your-custom-oko-sdk.example.com", // optional, Only specify if you have your own SDK endpoint
loginMethods: [
{ provider: "google" },
// optional, Specify which login providers to enable. If not specified, all available providers will be included
],
});
```

Expand All @@ -61,10 +56,10 @@ wallets:

```typescript
import { ChainProvider } from "@cosmos-kit/react";
import { makeOkoWallets } from "@oko-wallet/oko-cosmos-kit";
import { makeOkoWallet } from "@oko-wallet/oko-cosmos-kit";
import { chains, assets } from "chain-registry";

const okoWallets = makeOkoWallets({
const okoWallet = makeOkoWallet({
apiKey: "your-oko-api-key",
});

Expand All @@ -73,7 +68,7 @@ export default function App({ Component, pageProps }) {
<ChainProvider
chains={chains}
assetLists={assets}
wallets={[...okoWallets]}
wallets={[okoWallet]}
>
<Component {...pageProps} />
</ChainProvider>
Expand Down Expand Up @@ -116,7 +111,7 @@ function WalletConnect() {

### OkoWalletOptions

The `makeOkoWallets` function accepts the following options:
The `makeOkoWallet` function accepts the following options:

```typescript
interface OkoWalletOptions {
Expand All @@ -126,31 +121,18 @@ interface OkoWalletOptions {
// Custom SDK endpoint (optional)
// Defaults to Oko's production endpoint
sdkEndpoint?: string;

// Login methods to enable (optional)
// If not specified, all available providers will be enabled
loginMethods?: OkoLoginMethod[];
}

interface OkoLoginMethod {
provider: SignInType;
}

type SignInType = "google" | "email" | "x" | "telegram" | "discord";
```

### Login Providers

Each login provider creates a separate wallet entry in Cosmos Kit's wallet list:

- `oko_wallet_google` - Google OAuth login
- `oko_wallet_email` - Email/passwordless login
- `oko_wallet_x` - X (Twitter) OAuth login
- `oko_wallet_telegram` - Telegram login
- `oko_wallet_discord` - Discord OAuth login
When connecting, users can select their preferred login provider from a modal:

When `loginMethods` is not specified, all available providers are automatically
included.
- Google OAuth
- Email/passwordless
- X (Twitter) OAuth
- Telegram OAuth
- Discord OAuth

## Next Steps

Expand Down
48 changes: 14 additions & 34 deletions apps/docs_web/docs/v0/sdk-usage/interchain-kit-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,16 @@ npm install @oko-wallet/oko-interchain-kit @interchain-kit/react @interchain-kit

## Basic Setup

### 1. Create Oko Wallets
### 1. Create Oko Wallet

Use `makeOkoWallets` to generate wallet instances for your desired login
providers:
Use `makeOkoWallet` to create a wallet instance:

```typescript
import { makeOkoWallets } from "@oko-wallet/oko-interchain-kit";
import { makeOkoWallet } from "@oko-wallet/oko-interchain-kit";

const okoWallets = makeOkoWallets({
const okoWallet = makeOkoWallet({
apiKey: "your-oko-api-key",
sdkEndpoint: "https://your-custom-oko-sdk.example.com", // optional, Only specify if you have your own SDK endpoint
loginMethods: [
{ provider: "google" },
{ provider: "email" },
// optional, Specify which login providers to enable. If not specified, all available providers will be included
],
});
```

Expand All @@ -59,10 +53,10 @@ wallets:

```typescript
import { ChainProvider } from "@interchain-kit/react";
import { makeOkoWallets } from "@oko-wallet/oko-interchain-kit";
import { makeOkoWallet } from "@oko-wallet/oko-interchain-kit";
import { chains, assetLists } from "@chain-registry/v2";

const okoWallets = makeOkoWallets({
const okoWallet = makeOkoWallet({
apiKey: "your-oko-api-key",
});

Expand All @@ -71,7 +65,7 @@ export default function App({ Component, pageProps }) {
<ChainProvider
chains={chains}
assetLists={assetLists}
wallets={[...okoWallets]}
wallets={[okoWallet]}
>
<Component {...pageProps} />
</ChainProvider>
Expand Down Expand Up @@ -109,7 +103,7 @@ function WalletConnect() {

### OkoWalletOptions

The `makeOkoWallets` function accepts the following options:
The `makeOkoWallet` function accepts the following options:

```typescript
interface OkoWalletOptions {
Expand All @@ -119,32 +113,18 @@ interface OkoWalletOptions {
// Custom SDK endpoint (optional)
// Defaults to Oko's production endpoint
sdkEndpoint?: string;

// Login methods to enable (optional)
// If not specified, all available providers will be enabled
loginMethods?: OkoLoginMethod[];
}

interface OkoLoginMethod {
provider: SignInType;
}

type SignInType = "google" | "email" | "x" | "telegram" | "discord";
```

### Login Providers

Each login provider creates a separate wallet entry in Interchain Kit's wallet
list:

- `oko-wallet_google` - Google OAuth login
- `oko-wallet_email` - Email/passwordless login
- `oko-wallet_x` - X (Twitter) OAuth login
- `oko-wallet_telegram` - Telegram login
- `oko-wallet_discord` - Discord OAuth login
When connecting, users can select their preferred login provider from a modal:

When `loginMethods` is not specified, all available providers are automatically
included.
- Google OAuth
- Email/passwordless
- X (Twitter) OAuth
- Telegram OAuth
- Discord OAuth

## Signing Transactions

Expand Down
2 changes: 1 addition & 1 deletion apps/email_template_2/src/app/reset_pw_code/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export default function ResetPwCodePage() {
password.
<br />
The code is valid for{" "}
{"${email_verification_expiration_minutes}"} minutes
{"${email_verification_expiration_minutes}"} minute
for your security.
</EmailText>
</td>
Expand Down
2 changes: 2 additions & 0 deletions backend/ct_dashboard_api/src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
export const PASSWORD_MIN_LENGTH = 4;
export const CHANGED_PASSWORD_MIN_LENGTH = 8;
export const CHANGED_PASSWORD_MAX_LENGTH = 16;
export const PASSWORD_CONTAINS_NUMBER_REGEX = /\d/;

export const SIX_DIGITS_REGEX = /^\d{6}$/;

Expand Down
2 changes: 1 addition & 1 deletion backend/ct_dashboard_api/src/email/password_reset.ts

Large diffs are not rendered by default.

Loading