SaveButton.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import React, { Component } from "react";
  2. import styled from "styled-components";
  3. import loading from "assets/loading.gif";
  4. type PropsType = {
  5. text: string;
  6. onClick: () => void;
  7. disabled?: boolean;
  8. status?: string | null;
  9. color?: string;
  10. helper?: string | null;
  11. // Makes flush with corner if not within a modal
  12. makeFlush?: boolean;
  13. };
  14. type StateType = {};
  15. export default class SaveButton extends Component<PropsType, StateType> {
  16. renderStatus = () => {
  17. if (this.props.status) {
  18. if (this.props.status === "successful") {
  19. return (
  20. <StatusWrapper successful={true}>
  21. <i className="material-icons">done</i> Successfully updated
  22. </StatusWrapper>
  23. );
  24. } else if (this.props.status === "loading") {
  25. return (
  26. <StatusWrapper successful={false}>
  27. <LoadingGif src={loading} /> Updating . . .
  28. </StatusWrapper>
  29. );
  30. } else if (this.props.status === "error") {
  31. return (
  32. <StatusWrapper successful={false}>
  33. <i className="material-icons">error_outline</i> Could not update
  34. </StatusWrapper>
  35. );
  36. } else {
  37. return (
  38. <StatusWrapper successful={false}>
  39. <i className="material-icons">error_outline</i> {this.props.status}
  40. </StatusWrapper>
  41. );
  42. }
  43. } else if (this.props.helper) {
  44. return (
  45. <StatusWrapper successful={true}>{this.props.helper}</StatusWrapper>
  46. );
  47. }
  48. };
  49. render() {
  50. return (
  51. <ButtonWrapper makeFlush={this.props.makeFlush}>
  52. {this.renderStatus()}
  53. <Button
  54. disabled={this.props.disabled}
  55. onClick={this.props.onClick}
  56. color={this.props.color || "#616FEEcc"}
  57. >
  58. {this.props.text}
  59. </Button>
  60. </ButtonWrapper>
  61. );
  62. }
  63. }
  64. const LoadingGif = styled.img`
  65. width: 15px;
  66. height: 15px;
  67. margin-right: 9px;
  68. margin-bottom: 0px;
  69. `;
  70. const StatusWrapper = styled.div`
  71. display: flex;
  72. align-items: center;
  73. font-family: "Work Sans", sans-serif;
  74. font-size: 13px;
  75. color: #ffffff55;
  76. margin-right: 25px;
  77. > i {
  78. font-size: 18px;
  79. margin-right: 10px;
  80. color: ${(props: { successful: boolean }) =>
  81. props.successful ? "#4797ff" : "#fcba03"};
  82. }
  83. animation: statusFloatIn 0.5s;
  84. animation-fill-mode: forwards;
  85. @keyframes statusFloatIn {
  86. from {
  87. opacity: 0;
  88. transform: translateY(10px);
  89. }
  90. to {
  91. opacity: 1;
  92. transform: translateY(0px);
  93. }
  94. }
  95. `;
  96. const ButtonWrapper = styled.div`
  97. display: flex;
  98. align-items: center;
  99. position: absolute;
  100. ${(props: { makeFlush: boolean }) => {
  101. if (!props.makeFlush) {
  102. return `
  103. bottom: 25px;
  104. right: 27px;
  105. `;
  106. }
  107. return `
  108. bottom: 0;
  109. right: 0;
  110. `;
  111. }}
  112. `;
  113. const Button = styled.button`
  114. height: 35px;
  115. font-size: 13px;
  116. font-weight: 500;
  117. font-family: "Work Sans", sans-serif;
  118. color: white;
  119. padding: 6px 20px 7px 20px;
  120. text-align: left;
  121. border: 0;
  122. border-radius: 5px;
  123. background: ${props => (!props.disabled ? props.color : "#aaaabb")};
  124. box-shadow: ${props => (!props.disabled ? "0 2px 5px 0 #00000030" : "none")};
  125. cursor: ${props => (!props.disabled ? "pointer" : "default")};
  126. user-select: none;
  127. :focus {
  128. outline: 0;
  129. }
  130. :hover {
  131. filter: ${props => (!props.disabled ? "brightness(120%)" : "")};
  132. }
  133. `;