Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SDP-902 - Release 1.0.0 to develop #33

Merged
merged 4 commits into from
Oct 19, 2023
Merged
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
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,35 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

> Place unreleased changes here.

## [1.0.0](https://github.com/stellar/stellar-disbursement-platform-backend/compare/1.0.0-rc2...1.0.0)

### Added

- Add a new screen to manage Wallet Providers.
[#14](https://github.com/stellar/stellar-disbursement-platform-frontend/pull/14)
- Add re-send SMS invitation functionality.
[#18](https://github.com/stellar/stellar-disbursement-platform-frontend/pull/18)
- Customize receiver wallet invite SMS message.
[#17](https://github.com/stellar/stellar-disbursement-platform-frontend/pull/17)
- Display asset issuer for Trustlines in the Distribution account screen
[#20](https://github.com/stellar/stellar-disbursement-platform-frontend/pull/20)
- Settings: configure SMS retry interval
[#28](https://github.com/stellar/stellar-disbursement-platform-frontend/pull/28)

### Changed

- Change payment status history sort order to descending order.
[#15](https://github.com/stellar/stellar-disbursement-platform-frontend/pull/15)
- Filter assets based on wallet selection in New Disbursement screen.
[#24](https://github.com/stellar/stellar-disbursement-platform-frontend/pull/24)
- Only show enabled wallets in the New Disbursement screen.
[#29](https://github.com/stellar/stellar-disbursement-platform-frontend/pull/29)

### Security

- Add warning message about Distribution account funds
[#11](https://github.com/stellar/stellar-disbursement-platform-frontend/pull/11)

## [1.0.0.rc2](https://github.com/stellar/stellar-disbursement-platform-backend/compare/1.0.0-rc1...1.0.0-rc2)

### Added
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "stellar-disbursement-platform-frontend",
"version": "1.0.0-rc2",
"version": "1.0.0",
"license": "Apache-2.0",
"engines": {
"node": ">=18.x"
Expand Down
37 changes: 37 additions & 0 deletions src/apiQueries/useUpdateOrgSmsRetryInterval.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useMutation } from "@tanstack/react-query";
import { API_URL } from "constants/settings";
import { fetchApi } from "helpers/fetchApi";
import { AppError } from "types";

export const useUpdateOrgSmsRetryInterval = () => {
const mutation = useMutation({
mutationFn: (retryInterval: number) => {
const formData = new FormData();

formData.append("data", `{"sms_resend_interval": ${retryInterval}}`);

return fetchApi(
`${API_URL}/organization`,
{
method: "PATCH",
body: formData,
},
{ omitContentType: true },
);
},
cacheTime: 0,
});

return {
...mutation,
error: mutation.error as AppError,
data: mutation.data as { message: string },
mutateAsync: async (retryInterval: number) => {
try {
await mutation.mutateAsync(retryInterval);
} catch (e) {
// do nothing
}
},
};
};
156 changes: 156 additions & 0 deletions src/components/SettingsEnableSmsRetry.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import { useEffect, useState } from "react";
import {
Button,
Card,
Input,
Notification,
Toggle,
Loader,
} from "@stellar/design-system";
import { useDispatch } from "react-redux";

import { DropdownMenu } from "components/DropdownMenu";
import { MoreMenuButton } from "components/MoreMenuButton";

import { useUpdateOrgSmsRetryInterval } from "apiQueries/useUpdateOrgSmsRetryInterval";
import { useRedux } from "hooks/useRedux";
import { AppDispatch } from "store";
import { getOrgInfoAction } from "store/ducks/organization";

export const SettingsEnableSmsRetry = () => {
const { organization } = useRedux("organization");

const [smsRetryInterval, setSmsRetryInterval] = useState(0);
const [isEditMode, setIsEditMode] = useState(false);

const dispatch: AppDispatch = useDispatch();

const { mutateAsync, isLoading, error, isSuccess } =
useUpdateOrgSmsRetryInterval();

useEffect(() => {
setSmsRetryInterval(organization.data.smsResendInterval);
}, [organization.data.smsResendInterval]);

useEffect(() => {
if (isSuccess) {
dispatch(getOrgInfoAction());
setIsEditMode(false);
}
}, [dispatch, isSuccess]);

const handleToggleChange = () => {
// Default interval is 2 days
mutateAsync(organization.data.smsResendInterval === 0 ? 2 : 0);
};

const handleSmsRetrySubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
mutateAsync(smsRetryInterval);
};

const handleSmsRetryReset = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
setIsEditMode(false);
setSmsRetryInterval(organization.data.smsResendInterval);
};

const renderContent = () => {
return (
<div className="SdpSettings">
<div className="SdpSettings__row">
<div className="SdpSettings__item">
<label className="SdpSettings__label" htmlFor="sms-retry">
Enable automatic SMS retry
</label>
<div className="Toggle__wrapper">
{isLoading ? <Loader size="1rem" /> : null}
<Toggle
id="sms-retry"
checked={Boolean(organization.data.smsResendInterval)}
onChange={handleToggleChange}
disabled={isLoading}
/>
</div>
</div>
<div className="Note">
Select this option to automatically re-send the SMS invitation to
unregistered receivers after a certain time period. They will
receive the same message again. The message will only go to
receivers who have not registered their wallet.
</div>
</div>

{organization.data.smsResendInterval ? (
<div className="SdpSettings__row">
<form
className="SdpSettings__form"
onSubmit={handleSmsRetrySubmit}
onReset={handleSmsRetryReset}
>
<div className="SdpSettings__form__row">
<Input
fieldSize="sm"
id="sms-retry-interval"
label="SMS retry interval (days)"
type="number"
value={smsRetryInterval}
onChange={(e) => setSmsRetryInterval(Number(e.target.value))}
disabled={!isEditMode}
error={
smsRetryInterval === 0 ? "Retry interval cannot be 0" : ""
}
/>
{!isEditMode ? (
<DropdownMenu triggerEl={<MoreMenuButton />}>
<DropdownMenu.Item onClick={() => setIsEditMode(true)}>
Edit
</DropdownMenu.Item>
</DropdownMenu>
) : null}
</div>
{isEditMode ? (
<div className="SdpSettings__form__buttons">
<Button
variant="secondary"
size="xs"
type="reset"
isLoading={isLoading}
>
Cancel
</Button>
<Button
variant="primary"
size="xs"
type="submit"
isLoading={isLoading}
disabled={
!smsRetryInterval ||
smsRetryInterval === organization.data.smsResendInterval
}
>
Update
</Button>
</div>
) : null}
</form>
</div>
) : null}
</div>
);
};

return (
<>
{error ? (
<Notification variant="error" title="Error">
{error.message}
</Notification>
) : null}

<Card>
<div className="CardStack__card">{renderContent()}</div>
</Card>
</>
);
};
4 changes: 2 additions & 2 deletions src/helpers/validateNewPassword.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ export const validateNewPassword = (password: string): string => {

if (!password) {
errorMsg = "Password is required";
} else if (password.length < 8) {
errorMsg = "Password must be at least 8 characters long";
} else if (password.length < 12) {
errorMsg = "Password must be at least 12 characters long";
} else if (!passwordStrength.test(password)) {
errorMsg =
"Password must have at least one uppercase letter, lowercase letter, number, and symbol.";
Expand Down
14 changes: 11 additions & 3 deletions src/pages/ResetPassword.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,16 @@ export const ResetPassword = () => {

{forgotPassword.errorString && (
<Notification variant="error" title="Reset password error">
{forgotPassword.errorString}. Check your email for the correct
token.
{forgotPassword.errorString}
{forgotPassword.errorExtras ? (
<ul className="ErrorExtras">
{Object.entries(forgotPassword.errorExtras).map(
([key, value]) => (
<li key={key}>{`${key}: ${value}`}</li>
),
)}
</ul>
) : null}
</Notification>
)}

Expand All @@ -95,7 +103,7 @@ export const ResetPassword = () => {
<div className="Note">
New password must be:
<ul>
<li>at least 8 characters long,</li>
<li>at least 12 characters long,</li>
<li>
a combination of uppercase letters, lowercase letters,
numbers, and symbols.
Expand Down
2 changes: 1 addition & 1 deletion src/pages/SetNewPassword.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export const SetNewPassword = () => {
<div className="Note">
New password must be:
<ul>
<li>at least 8 characters long,</li>
<li>at least 12 characters long,</li>
<li>
a combination of uppercase letters, lowercase letters,
numbers, and symbols.
Expand Down
10 changes: 8 additions & 2 deletions src/pages/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { SectionHeader } from "components/SectionHeader";
import { NotificationWithButtons } from "components/NotificationWithButtons";
import { SettingsTeamMembers } from "components/SettingsTeamMembers";
import { ReceiverInviteMessage } from "components/ReceiverInviteMessage";
import { SettingsEnableSmsRetry } from "components/SettingsEnableSmsRetry";

import { AppDispatch } from "store";
import { resetNewUserAction, resetUpdatedUserAction } from "store/ducks/users";
Expand Down Expand Up @@ -61,6 +62,13 @@ export const Settings = () => {
</SectionHeader>

<div className="CardStack">
{/* Enable SMS retry */}
<SettingsEnableSmsRetry />

{/* Customize receiver wallet invite */}
<ReceiverInviteMessage />

{/* Team members */}
{users.updatedUser.status === "SUCCESS" ? (
<NotificationWithButtons
variant="success"
Expand Down Expand Up @@ -105,8 +113,6 @@ export const Settings = () => {
</Notification>
) : null}

<ReceiverInviteMessage />

{users.errorString ? (
<Notification variant="error" title="Error">
{users.errorString}
Expand Down
2 changes: 2 additions & 0 deletions src/store/ducks/organization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ const initialState: OrganizationInitialState = {
timezoneUtcOffset: "",
assetBalances: undefined,
isApprovalRequired: undefined,
smsResendInterval: 0,
},
updateMessage: undefined,
status: undefined,
Expand Down Expand Up @@ -161,6 +162,7 @@ const organizationSlice = createSlice({
isApprovalRequired: action.payload.is_approval_required,
smsRegistrationMessageTemplate:
action.payload.sms_registration_message_template,
smsResendInterval: Number(action.payload.sms_resend_interval || 0),
};
state.status = "SUCCESS";
});
Expand Down
Loading
Loading