diff --git a/react-native/src/App.tsx b/react-native/src/App.tsx index 169e7c12b..2f06f5525 100644 --- a/react-native/src/App.tsx +++ b/react-native/src/App.tsx @@ -13,39 +13,23 @@ import { Provider } from 'mobx-react'; import initializeStores from './stores/storeInitializer'; import RoutingContainer from './components/routing/routingConfig'; - - - const stores = initializeStores(); console.disableYellowBox = true; -interface Props { - -} +interface Props {} interface State { - appState:any + appState: any; } -export default class App extends React.Component { +export default class App extends React.Component { constructor(props) { super(props); } - render() { - return ( - + ); } } - - - - - - - - - diff --git a/react-native/src/components/loader/loader.tsx b/react-native/src/components/loader/loader.tsx index 8eb05f5cd..4aa91e314 100644 --- a/react-native/src/components/loader/loader.tsx +++ b/react-native/src/components/loader/loader.tsx @@ -1,46 +1,46 @@ -import React from 'react'; +import React from 'react'; import { StyleSheet, View, Modal, ActivityIndicator } from 'react-native'; interface Props { - loading: boolean + loading: boolean; } const Loader = (props: Props) => { - const { loading } = props; - return ( - { - console.log('close modal'); - }} - > - - - - - - - ) -} + const { loading } = props; + return ( + { + console.log('close modal'); + }} + > + + + + + + + ); +}; const styles = StyleSheet.create({ - modalBackground: { - flex: 1, - alignItems: 'center', - flexDirection: 'column', - justifyContent: 'space-around', - backgroundColor: 'rgba(191, 191, 191, 0.5)', - }, - activityIndicatorWrapper: { - backgroundColor: '#000000', - height: 100, - width: 100, - borderRadius: 10, - display: 'flex', - alignItems: 'center', - justifyContent: 'space-around', - }, + modalBackground: { + flex: 1, + alignItems: 'center', + flexDirection: 'column', + justifyContent: 'space-around', + backgroundColor: 'rgba(191, 191, 191, 0.5)', + }, + activityIndicatorWrapper: { + backgroundColor: '#000000', + height: 100, + width: 100, + borderRadius: 10, + display: 'flex', + alignItems: 'center', + justifyContent: 'space-around', + }, }); export default Loader; diff --git a/react-native/src/components/routing/routingConfig.tsx b/react-native/src/components/routing/routingConfig.tsx index 77e8d5e7d..5eb89b6d2 100644 --- a/react-native/src/components/routing/routingConfig.tsx +++ b/react-native/src/components/routing/routingConfig.tsx @@ -13,13 +13,15 @@ import Setting from '../../scenes/Setting/setting'; import { httpServiceFunc } from '../../services/httpService'; import { Root, Button, Icon } from 'native-base'; import { CreateOrEditTenant } from '../../scenes/Tenants/createOrEditTenant'; +import { CreateOrEditRole } from '../../scenes/Roles/createOrEditRole'; +import CreateOrEdituser from '../../scenes/Users/createOrEditUser'; const AuthStack2 = createStackNavigator( { Dashboard: { screen: Dasboard, }, - User: { + Users: { screen: Users, }, Tenants: { @@ -34,9 +36,15 @@ const AuthStack2 = createStackNavigator( CreateOrEditTenant: { screen: CreateOrEditTenant, }, + CreateOrEditRoles: { + screen: CreateOrEditRole, + }, + CreateOrEditUser: { + screen: CreateOrEdituser, + }, }, { - initialRouteName: 'User', + initialRouteName: 'Roles', defaultNavigationOptions: ({ navigation }) => ({ headerLeft: ( - - )} - - {}} style={styles.textButton}> - Forget Password + + + + + + + Geçerli müşteri: + {this.state.tenancyName} + this.toggleTenantModal()}> + (Değiştir) - + + this.login({ + userNameOrEmailAddress: value.email, + password: value.password, + rememberMe: true, + }) + } + > + {({ handleChange, values, handleSubmit, errors, handleBlur }) => ( + <> + this.password.focus()} + onBlur={handleBlur} + returnKeyType="next" + keyboardType="email-address" + value={values.email} + onChangeText={handleChange('email')} + /> + {errors.email && {errors.email}} + { + this.password = ref; + }} + placeholder="Password" + onSubmitEditing={() => handleSubmit()} + secureTextEntry={true} + keyboardType="default" + value={values.password} + onChangeText={handleChange('password')} + /> + {errors.password && {errors.password}} + + + )} + + {}} style={styles.textButton}> + Forget Password + + this.isTenanAvaible(tenantName)} toggleModal={() => this.toggleTenantModal()} /> - + ); } } diff --git a/react-native/src/scenes/Roles/createOrEditRole.tsx b/react-native/src/scenes/Roles/createOrEditRole.tsx new file mode 100644 index 000000000..96a4043af --- /dev/null +++ b/react-native/src/scenes/Roles/createOrEditRole.tsx @@ -0,0 +1,275 @@ +import React from 'react'; +import { NavigationScreenProp, NavigationRoute } from 'react-navigation'; +import { + Container, + Card, + CardItem, + Body, + Content, + Button, + Item, + Input, + Icon, + Label, + Text, + View, +} from 'native-base'; +import { StyleSheet, Switch, Dimensions } from 'react-native'; +import Stores from '../../stores/storeIdentifier'; +import { Formik } from 'formik'; +import * as yup from 'yup'; +import { observer, inject } from 'mobx-react'; +import { _toast } from '../../utils/utils'; +import RoleStore from '../../stores/roleStore'; +import { GetAllPermissionsOutput } from '../../services/role/dto/getAllPermissionsOutput'; + +export interface Params { + id: string; +} + +export interface Props { + roleStore?: RoleStore; + navigation: NavigationScreenProp, Params>; +} + +interface RoleSwitch { + name: string; + displayName: string; + value: boolean; +} + +export interface State {} + +@inject(Stores.RoleStore) +@observer +export class CreateOrEditRole extends React.Component { + name: any; + description: any; + displayName: any; + constructor(props) { + super(props); + } + + static navigationOptions = ({ + navigation, + }: { + navigation: NavigationScreenProp, Params>; + }) => { + return { + title: ( + {navigation.getParam('id') == '' ? 'Create' : 'Edit'} + ), + headerLeft: ( + + ), + }; + }; + + isEdit = (): boolean => { + return this.props.navigation.getParam('id') !== ''; + }; + + async componentWillMount() { + if (this.isEdit()) { + await this.props.roleStore.getRoleForEdit({ + id: parseInt(this.props.navigation.getParam("id")), + }); + await this.props.roleStore.getAllPermissions(); + } else { + this.props.roleStore.createRole(); + await this.props.roleStore.getAllPermissions(); + } + } + createOrUpdateRole = async values => { + const roleName = values.grantedPermissions + .filter((x: RoleSwitch) => x.value === true) + .map((x: RoleSwitch) => x.name); + if (this.isEdit()) { + await this.props.roleStore + .update({ + id: parseInt(this.props.navigation.getParam('id')), + ...values, + grantedPermissions: roleName, + }) + .then(() => _toast('Update başarılı', 'success')); + } else { + await this.props.roleStore + .create({ ...values, grantedPermissions: roleName }) + .then(() => _toast('Role Oluşturuldu', 'success')); + } + }; + + render() { + const { roleEdit, allPermissions } = this.props.roleStore!; + + const grantedPermissions = allPermissions.map((x: GetAllPermissionsOutput) => { + if (roleEdit.grantedPermissionNames.indexOf(x.name) !== -1) { + return { value: true, name: x.name, displayName: x.displayName }; + } else { + return { value: false, name: x.name, displayName: x.displayName }; + } + }); + return ( + + + + + + this.createOrUpdateRole(value)} + > + {({ + handleChange, + values, + handleSubmit, + errors, + handleBlur, + setFieldValue, + isValid, + }) => ( + <> + + + this.name._root.focus()} + value={values.displayName} + onChangeText={handleChange('displayName')} + /> + {errors.displayName ? ( + + ) : ( + + )} + + + + this.description._root.focus()} + onBlur={handleBlur} + getRef={(ref: any) => { + this.name = ref; + }} + returnKeyType="next" + value={values.name} + onChangeText={handleChange('name')} + /> + {errors.name ? ( + + ) : ( + + )} + + + + { + this.description = ref; + }} + returnKeyType="done" + onSubmitEditing={() => handleSubmit()} + onBlur={handleBlur} + value={values.description} + onChangeText={handleChange('description')} + /> + {errors.description ? ( + + ) : ( + + )} + + + {values.grantedPermissions.map((x: RoleSwitch, index) => ( + + + setFieldValue(`grantedPermissions[${index}]`, { + ...x, + value: value, + }) + } + /> + + + ))} + + + + )} + + + + + + + ); + } +} + +const styles = StyleSheet.create({ + marginVrtcl: { + marginVertical: 5, + }, +}); +export default CreateOrEditRole; diff --git a/react-native/src/scenes/Roles/roles.tsx b/react-native/src/scenes/Roles/roles.tsx index cdb5063a4..82e344a16 100644 --- a/react-native/src/scenes/Roles/roles.tsx +++ b/react-native/src/scenes/Roles/roles.tsx @@ -1,33 +1,224 @@ -import React from 'react'; -import {Text} from 'react-native'; -import { Button } from 'native-base'; -import { NavigationStackProp } from 'react-navigation-stack'; - +import React from "react"; +import { + View, + Fab, + Icon, + Container, + Button, + Text, + ActionSheet, + Header, + Item, + Input, + Right, +} from "native-base"; +import { NavigationStackProp } from "react-navigation-stack"; +import RoleStore from "../../stores/roleStore"; +import { StyleSheet, RefreshControl } from "react-native"; +import { observer, inject } from "mobx-react"; +import Stores from "../../stores/storeIdentifier"; +import { SwipeListView } from "react-native-swipe-list-view"; export interface Props { navigation: NavigationStackProp; + roleStore: RoleStore; } +import { NavigationScreenProp, NavigationRoute } from "react-navigation"; export interface State { - + reflesing: boolean; + maxResultCount: number; + skipCount: number; + keyword: string; +} +export interface Params { + count: string; } - +@inject(Stores.RoleStore) +@observer export class Roles extends React.Component { - constructor(props) { super(props); + this.state = { reflesing: false, maxResultCount: 10, skipCount: 0, keyword: '' }; + } + static navigationOptions = ({ + navigation, + }: { + navigation: NavigationScreenProp, Params>; + }) => { + return { + headerRight: ( + {navigation.getParam('count')} + ), + }; + }; + async componentWillMount() { + await this.getAll(); + const { roles } = this.props.roleStore!; + this.props.navigation.setParams({ + count: roles === undefined ? 0 : roles.totalCount, + }); + } + async getAll() { + const { maxResultCount, keyword, skipCount } = this.state; + await this.props.roleStore!.getAll({ + maxResultCount: maxResultCount, + skipCount: skipCount * maxResultCount, + keyword: keyword, + }); + } + + async handleReflesh() { + this.setState( + { reflesing: true }, + async () => + await this.props + .roleStore!.getAll({ maxResultCount: 10, skipCount: 0, keyword: "" }) + .then(() => this.setState({ reflesing: false })), + ); } render() { + const { roles } = this.props.roleStore!; + const { maxResultCount, skipCount } = this.state; return ( - - Roles + +
+ + + this.getAll()} + onChange={e => this.setState({ keyword: e.nativeEvent.text, skipCount: 0 })} + /> + + + + +
+ + maxResultCount + skipCount * maxResultCount < + (roles === undefined ? 0 : roles.totalCount) && ( + + ) + } + keyExtractor={(x, i) => i.toString()} + onEndReachedThreshold={0} + showsVerticalScrollIndicator={false} + refreshControl={ + this.handleReflesh()} + /> + } + data={roles === undefined ? [] : roles.items} + renderItem={data => ( + + {data.item.name} + + )} + renderHiddenItem={data => ( + + + + + )} + leftOpenValue={75} + rightOpenValue={-75} + /> + + + this.props.navigation.navigate('CreateOrEditRoles', { + id: "", + }) + } + > + + + +
); } } +const styles = StyleSheet.create({ + rowFront: { + alignItems: "center", + backgroundColor: "#F5F5F5", + borderBottomColor: "#BDBDBD", + borderBottomWidth: 1, + justifyContent: "center", + height: 50, + }, + rowBack: { + alignItems: "center", + flex: 1, + flexDirection: "row", + justifyContent: "space-between", + }, + rowBackLeft: { + width: 75, + backgroundColor: '#303F9F', + margin: 0, + borderRadius: 0, + justifyContent: 'center', + }, + rowBackRight: { + width: 75, + backgroundColor: '#d32f2f', + margin: 0, + borderRadius: 0, + justifyContent: 'center', + }, + editIcon: { + color: '#fff', + }, + trashIcon: { + color: '#fff', + }, +}); - -export default Roles; \ No newline at end of file +export default Roles; diff --git a/react-native/src/scenes/Setting/setting.tsx b/react-native/src/scenes/Setting/setting.tsx index a9f4bde82..7c8f16fba 100644 --- a/react-native/src/scenes/Setting/setting.tsx +++ b/react-native/src/scenes/Setting/setting.tsx @@ -12,20 +12,25 @@ import { Icon, Label, Text, + Tabs, + Tab, + Form, + Picker, } from 'native-base'; import { StyleSheet } from 'react-native'; import Stores from '../../stores/storeIdentifier'; -import AccountStore from '../../stores/accountStore'; import { Formik } from 'formik'; import * as yup from 'yup'; +import UserStore from '../../stores/userStore'; +import { _toast } from '../../utils/utils'; export interface Props { - accountStore?: AccountStore; + userStore?: UserStore; } export interface State {} -@inject(Stores.AccountStore) +@inject(Stores.UserStore) @observer export class Setting extends React.Component { newpassword: any; @@ -34,113 +39,168 @@ export class Setting extends React.Component { super(props); } + getRandomColor = () => { + var letters = '0123456789ABCDEF'; + var color = '#'; + for (var i = 0; i < 6; i++) { + color += letters[Math.floor(Math.random() * 16)]; + } + return color; + }; + + changePassword = async values => { + await this.props + .userStore!.changePassword({ + currentPassword: values.currentPassword, + newPassword: values.newPassword, + }) + .then(() => _toast('Şifre Değiştirildi', 'success')); + }; + render() { return ( - - - Change Password - - - - console.log(value.currentPassword)} - > - {({ handleChange, values, handleSubmit, errors, handleBlur }) => ( - <> - - - this.newpassword.focus()} - onBlur={handleBlur} - returnKeyType="next" - secureTextEntry={true} - value={values.currentPassword} - onChangeText={handleChange('currentPassword')} - /> - {errors.currentPassword ? ( - - ) : ( - - )} - - - - this.newpasswordConfirm.focus()} - onBlur={handleBlur} - ref={(ref: any) => { - this.newpassword = ref; - }} - returnKeyType="next" - secureTextEntry={true} - value={values.newPassword} - onChangeText={handleChange('newPassword')} - /> - {errors.newPassword ? ( - - ) : ( - - )} - - - - { - this.newpasswordConfirm = ref; - }} - returnKeyType="done" - onSubmitEditing={() => handleSubmit()} - onBlur={handleBlur} - secureTextEntry={true} - value={values.newPasswordConfirm} - onChangeText={handleChange('newPasswordConfirm')} - /> - {errors.newPasswordConfirm ? ( - - ) : ( - - )} - - - - )} - - - - + + + + + Change Password + + + + this.changePassword(values)} + > + {({ handleChange, values, handleSubmit, errors, handleBlur }) => ( + <> + + + this.newpassword.focus()} + onBlur={handleBlur} + returnKeyType="next" + secureTextEntry={true} + value={values.currentPassword} + onChangeText={handleChange('currentPassword')} + /> + {errors.currentPassword ? ( + + ) : ( + + )} + + + + this.newpasswordConfirm.focus()} + onBlur={handleBlur} + ref={(ref: any) => { + this.newpassword = ref; + }} + returnKeyType="next" + secureTextEntry={true} + value={values.newPassword} + onChangeText={handleChange('newPassword')} + /> + {errors.newPassword ? ( + + ) : ( + + )} + + + + { + this.newpasswordConfirm = ref; + }} + returnKeyType="done" + onSubmitEditing={() => handleSubmit()} + onBlur={handleBlur} + secureTextEntry={true} + value={values.newPasswordConfirm} + onChangeText={handleChange('newPasswordConfirm')} + /> + {errors.newPasswordConfirm ? ( + + ) : ( + + )} + + + + )} + + + + + + +
+ + } + style={{ width: undefined }} + placeholder="Select your SIM" + placeholderStyle={{ color: "#bfc6ea" }} + placeholderIconColor="#007aff" + selectedValue={"key0"} + > + + + + + + + +
+
+
); diff --git a/react-native/src/scenes/Tenants/createOrEditTenant.tsx b/react-native/src/scenes/Tenants/createOrEditTenant.tsx index 76c37de77..6f7478d3f 100644 --- a/react-native/src/scenes/Tenants/createOrEditTenant.tsx +++ b/react-native/src/scenes/Tenants/createOrEditTenant.tsx @@ -1,37 +1,278 @@ -import React from 'react'; -import { Button, View, Icon, Text } from 'native-base'; -import { NavigationScreenProp, NavigationRoute } from 'react-navigation'; - -export interface Props {} +import React from "react"; +import { NavigationScreenProp, NavigationRoute } from "react-navigation"; +import { + Container, + Card, + CardItem, + Body, + Content, + Button, + Item, + Input, + Icon, + Label, + Text, + View, +} from "native-base"; +import { StyleSheet, Switch } from "react-native"; +import Stores from "../../stores/storeIdentifier"; +import { Formik } from "formik"; +import * as yup from "yup"; +import { observer, inject } from "mobx-react"; +import TenantStore from "../../stores/tenantStore"; +import { _toast } from "../../utils/utils"; export interface Params { id: string; } +export interface Props { + tenantStore?: TenantStore; + navigation: NavigationScreenProp, Params>; +} + export interface State {} +@inject(Stores.TenantStore) +@observer export class CreateOrEditTenant extends React.Component { + name: any; + databaseConnectionString: any; + emailAdress: any; constructor(props) { super(props); } + static navigationOptions = ({ navigation, }: { navigation: NavigationScreenProp, Params>; }) => { return { + title: ( + {navigation.getParam("id") == "" ? "Create" : "Edit"} + ), headerLeft: ( - ), - // headerRight: {navigation.getParam('id')}, }; }; + isEdit = (): boolean => { + return this.props.navigation.getParam("id") !== ""; + }; + + async componentWillMount() { + this.isEdit() + ? await this.props + .tenantStore!.get({ id: parseInt(this.props.navigation.getParam('id')) }) + .catch(() => this.props.navigation.goBack()) + : this.props.tenantStore!.createTenant(); + } + createOrUpdateTenant = value => { + if (this.isEdit()) { + this.props + .tenantStore!.update({ + id: parseInt(this.props.navigation.getParam('id')), + tenancyName: value.tenancyName, + isActive: value.isActive, + name: value.name, + }) + .then(() => _toast('Update başarılı', 'success')); + } else { + this.props + .tenantStore!.create({ + tenancyName: value.tenancyName, + isActive: value.isActive, + name: value.name, + connectionString: value.databaseConnectionString, + adminEmailAddress: value.emailAdress, + }) + .then(() => _toast('Tenant Oluşturuldu', "success")); + } + }; + render() { - return ; + const { tenantModel } = this.props.tenantStore!; + return ( + + + + + + this.createOrUpdateTenant(value)} + > + {({ + handleChange, + values, + handleSubmit, + errors, + handleBlur, + setFieldValue, + isValid, + }) => ( + <> + + + this.name._root.focus()} + value={values.tenancyName} + onChangeText={handleChange("tenancyName")} + /> + {errors.tenancyName ? ( + + ) : ( + + )} + + + + + { + if (this.isEdit()) { + handleSubmit(); + } else { + this.databaseConnectionString._root.focus(); + } + }} + onBlur={handleBlur} + getRef={(ref: any) => { + this.name = ref; + }} + returnKeyType={this.isEdit() ? "done" : "next"} + value={values.name} + onChangeText={handleChange("name")} + /> + {errors.name ? ( + + ) : ( + + )} + + {!this.isEdit() && ( + + + this.emailAdress._root.focus()} + onBlur={handleBlur} + getRef={(ref: any) => { + this.databaseConnectionString = ref; + }} + returnKeyType="next" + value={values.databaseConnectionString} + onChangeText={handleChange("databaseConnectionString")} + /> + {errors.databaseConnectionString ? ( + + ) : ( + + )} + + )} + {!this.isEdit() && ( + + + { + this.emailAdress = ref; + }} + keyboardType="email-address" + returnKeyType="done" + onSubmitEditing={() => handleSubmit()} + onBlur={handleBlur} + value={values.emailAdress} + onChangeText={handleChange("emailAdress")} + /> + {errors.emailAdress ? ( + + ) : ( + + )} + + )} + + setFieldValue("isActive", value)} + /> + + + + {!this.isEdit() && } + + + + )} + + + + + + + ); } } +const styles = StyleSheet.create({ + marginVrtcl: { + marginVertical: 5, + }, +}); export default CreateOrEditTenant; diff --git a/react-native/src/scenes/Tenants/tenants.tsx b/react-native/src/scenes/Tenants/tenants.tsx index 6577c0237..e3cf9d026 100644 --- a/react-native/src/scenes/Tenants/tenants.tsx +++ b/react-native/src/scenes/Tenants/tenants.tsx @@ -1,28 +1,174 @@ -import React from 'react'; -import { View, Fab, Icon, Container } from 'native-base'; -import { NavigationStackProp } from 'react-navigation-stack'; - +import React from "react"; +import { + View, + Fab, + Icon, + Container, + Button, + Text, + ActionSheet, + Header, + Item, + Input, + Right, +} from "native-base"; +import { NavigationStackProp } from "react-navigation-stack"; +import TenantStore from "../../stores/tenantStore"; +import { StyleSheet, RefreshControl } from "react-native"; +import { observer, inject } from "mobx-react"; +import Stores from "../../stores/storeIdentifier"; +import { SwipeListView } from "react-native-swipe-list-view"; +import { NavigationScreenProp, NavigationRoute } from "react-navigation"; export interface Props { navigation: NavigationStackProp; + tenantStore: TenantStore; } -export interface State {} +export interface State { + reflesing: boolean; + maxResultCount: number; + skipCount: number; + keyword: string; +} +export interface Params { + count: string; +} +@inject(Stores.TenantStore) +@observer export class Tenants extends React.Component { constructor(props) { super(props); + this.state = { reflesing: false, maxResultCount: 10, skipCount: 0, keyword: '' }; + } + static navigationOptions = ({ + navigation, + }: { + navigation: NavigationScreenProp, Params>; + }) => { + return { + headerRight: ( + {navigation.getParam('count')} + ), + }; + }; + async componentWillMount() { + await this.getAll(); + const { tenants } = this.props.tenantStore!; + this.props.navigation.setParams({ + count: tenants === undefined ? 0 : tenants.totalCount, + }); + } + + async getAll() { + const { maxResultCount, keyword, skipCount } = this.state; + await this.props.tenantStore!.getAll({ + maxResultCount: maxResultCount, + skipCount: skipCount * maxResultCount, + keyword: keyword, + }); + } + + async handleReflesh() { + this.setState({ reflesing: true, skipCount: 0 }, async () => + this.getAll().then(() => this.setState({ reflesing: false })), + ); } render() { + const { tenants } = this.props.tenantStore!; + const { maxResultCount, skipCount } = this.state; + return ( +
+ + + this.getAll()} + onChange={e => this.setState({ keyword: e.nativeEvent.text, skipCount: 0 })} + /> + + + + +
+ + maxResultCount + skipCount * maxResultCount < + (tenants === undefined ? 0 : tenants.totalCount) && ( + + ) + } + keyExtractor={(x, i) => i.toString()} + onEndReachedThreshold={0} + showsVerticalScrollIndicator={false} + refreshControl={ + this.handleReflesh()} + /> + } + data={tenants === undefined ? [] : tenants.items} + renderItem={data => ( + + {data.item.tenancyName} + + )} + renderHiddenItem={data => ( + + + + + )} + leftOpenValue={75} + rightOpenValue={-75} + /> this.props.navigation.navigate('CreateOrEditTenant', { - id: "1", + id: "", }) } > @@ -34,4 +180,41 @@ export class Tenants extends React.Component { } } +const styles = StyleSheet.create({ + rowFront: { + alignItems: "center", + backgroundColor: "#F5F5F5", + borderBottomColor: "#BDBDBD", + borderBottomWidth: 1, + justifyContent: "center", + height: 50, + }, + rowBack: { + alignItems: "center", + flex: 1, + flexDirection: "row", + justifyContent: "space-between", + }, + rowBackLeft: { + width: 75, + backgroundColor: '#303F9F', + margin: 0, + borderRadius: 0, + justifyContent: 'center', + }, + rowBackRight: { + width: 75, + backgroundColor: '#d32f2f', + margin: 0, + borderRadius: 0, + justifyContent: 'center', + }, + editIcon: { + color: '#fff', + }, + trashIcon: { + color: '#fff', + }, +}); + export default Tenants; diff --git a/react-native/src/scenes/Users/createOrEditUser.tsx b/react-native/src/scenes/Users/createOrEditUser.tsx new file mode 100644 index 000000000..c93e95be3 --- /dev/null +++ b/react-native/src/scenes/Users/createOrEditUser.tsx @@ -0,0 +1,389 @@ +import React from "react"; +import { NavigationScreenProp, NavigationRoute } from "react-navigation"; +import { + Container, + Card, + CardItem, + Body, + Content, + Button, + Item, + Input, + Icon, + Label, + Text, + View, +} from "native-base"; +import { StyleSheet, Switch, Dimensions, Keyboard } from "react-native"; +import Stores from "../../stores/storeIdentifier"; +import { Formik } from "formik"; +import * as yup from "yup"; +import { observer, inject } from "mobx-react"; +import { _toast } from "../../utils/utils"; +import UserStore from "../../stores/userStore"; +import { GetRoles } from "../../services/user/dto/getRolesOuput"; + +export interface Params { + id: string; +} + +export interface Props { + userStore?: UserStore; + navigation: NavigationScreenProp, Params>; +} + +interface RoleSwitch { + name: string; + normalizedName: string; + value: boolean; +} + +export interface State {} + +@inject(Stores.UserStore) +@observer +export class CreateOrEdituser extends React.Component { + name: any; + surname: any; + emailAdress: any; + password: any; + confirmPassword: any; + constructor(props) { + super(props); + } + + static navigationOptions = ({ + navigation, + }: { + navigation: NavigationScreenProp, Params>; + }) => { + return { + title: ( + {navigation.getParam("id") == "" ? "Create" : "Edit"} + ), + headerLeft: ( + + ), + }; + }; + + isEdit = (): boolean => { + return this.props.navigation.getParam("id") !== ""; + }; + + async componentWillMount() { + if (this.isEdit()) { + await this.props.userStore.get({ id: parseInt(this.props.navigation.getParam('id')) }); + await this.props.userStore.getRoles(); + } else { + await this.props.userStore.createUser(); + await this.props.userStore.getRoles(); + } + } + + createOrUpdateTenant = async values => { + const roleName = values.roleNames + .filter((x: RoleSwitch) => x.value === true) + .map((x: RoleSwitch) => x.normalizedName); + + if (this.isEdit()) { + await this.props.userStore + .update({ id: this.props.navigation.getParam("id"), ...values, roleNames: roleName }) + .then(() => _toast('User Update Edildi', 'success')); + } else { + await this.props + .userStore!.create({ ...values, roleNames: roleName }) + .then(() => _toast('User Oluşturuldu', 'success')); + } + }; + + render() { + const { editUser, roles } = this.props.userStore!; + const grantedPermissions = roles.map((x: GetRoles) => { + if (editUser.roleNames.indexOf(x.normalizedName) !== -1) { + return { value: true, name: x.name, normalizedName: x.normalizedName }; + } else { + return { value: false, name: x.name, normalizedName: x.normalizedName }; + } + }); + return ( + + + + + + + {({ + handleChange, + values, + handleSubmit, + errors, + handleBlur, + setFieldValue, + isValid, + }) => ( + <> + + + this.name._root.focus()} + value={values.userName} + onChangeText={handleChange("userName")} + /> + {errors.userName ? ( + + ) : ( + + )} + + + + { + this.name = ref; + }} + onSubmitEditing={() => this.surname._root.focus()} + value={values.name} + onChangeText={handleChange("name")} + /> + {errors.name ? ( + + ) : ( + + )} + + + + { + this.emailAdress._root.focus(); + }} + onBlur={handleBlur} + getRef={(ref: any) => { + this.surname = ref; + }} + returnKeyType="next" + value={values.surname} + onChangeText={handleChange("surname")} + /> + {errors.surname ? ( + + ) : ( + + )} + + + + { + if (this.isEdit()) { + Keyboard.dismiss(); + } else { + this.password._root.focus(); + } + }} + keyboardType="email-address" + onBlur={handleBlur} + getRef={(ref: any) => { + this.emailAdress = ref; + }} + returnKeyType={this.isEdit() ? 'done' : 'next'} + value={values.emailAddress} + onChangeText={handleChange("emailAddress")} + /> + {errors.emailAddress ? ( + + ) : ( + + )} + + {!this.isEdit() && ( + + + { + this.password = ref; + }} + returnKeyType="next" + secureTextEntry={true} + onSubmitEditing={() => this.confirmPassword._root.focus()} + onBlur={handleBlur} + value={values.password} + onChangeText={handleChange("password")} + /> + {errors.password ? ( + + ) : ( + + )} + + )} + {!this.isEdit() && ( + + + { + this.confirmPassword = ref; + }} + returnKeyType="done" + secureTextEntry={true} + onSubmitEditing={() => Keyboard.dismiss()} + onBlur={handleBlur} + value={values.confirmPassword} + onChangeText={handleChange("confirmPassword")} + /> + {errors.confirmPassword ? ( + + ) : ( + + )} + + )} + + setFieldValue("isActive", value)} + /> + + + + + + + {values.roleNames.map((x: RoleSwitch, index) => { + return ( + + + setFieldValue(`roleNames[${index}]`, { + ...x, + value: value, + }) + } + /> + + + ); + })} + + + + )} + + + + + + + ); + } +} + +const styles = StyleSheet.create({ + marginVrtcl: { + marginVertical: 5, + }, +}); +export default CreateOrEdituser; diff --git a/react-native/src/scenes/Users/users.tsx b/react-native/src/scenes/Users/users.tsx index 50cd4a1f9..15ef1b103 100644 --- a/react-native/src/scenes/Users/users.tsx +++ b/react-native/src/scenes/Users/users.tsx @@ -1,41 +1,130 @@ import React, { Component } from 'react'; import { SwipeListView } from 'react-native-swipe-list-view'; -import { View, Text, Icon, Button, Container, Fab, ActionSheet } from 'native-base'; -import { StyleSheet } from 'react-native'; +import { + View, + Text, + Icon, + Button, + Container, + Fab, + ActionSheet, + Header, + Item, + Input, + Right, +} from 'native-base'; +import { StyleSheet, RefreshControl, Alert, ActivityIndicator } from 'react-native'; import UserStore from '../../stores/userStore'; import { observer, inject } from 'mobx-react'; import Stores from '../../stores/storeIdentifier'; import { NavigationStackProp } from 'react-navigation-stack'; - +import { NavigationScreenProp, NavigationRoute } from "react-navigation"; interface UsersProps { userStore: UserStore; navigation: NavigationStackProp; } -interface UsersState { } + +export interface UsersState { + reflesing: boolean; + maxResultCount: number; + skipCount: number; + keyword: string; +} +export interface Params { + count: string; +} @inject(Stores.UserStore) @observer class Users extends Component { constructor(props) { super(props); + this.state = { reflesing: false, maxResultCount: 10, skipCount: 0, keyword: '' }; } - + static navigationOptions = ({ + navigation, + }: { + navigation: NavigationScreenProp, Params>; + }) => { + return { + headerRight: ( + {navigation.getParam('count')} + ), + }; + }; async componentWillMount() { - await this.props.userStore!.getAll({ maxResultCount: 10, skipCount: 0, keyword: '' }); + await this.getAll(); + const { users } = this.props.userStore!; + this.props.navigation.setParams({ + count: users === undefined ? 0 : users.totalCount, + }); + } + async getAll() { + const { maxResultCount, keyword, skipCount } = this.state; + await this.props.userStore!.getAll({ + maxResultCount: maxResultCount, + skipCount: skipCount * maxResultCount, + keyword: keyword, + }); + } + + async handleReflesh() { + this.setState({ reflesing: true, skipCount: 0 }, async () => + this.getAll().then(() => this.setState({ reflesing: false })), + ); } render() { const { users } = this.props.userStore!; + const { maxResultCount, skipCount } = this.state; + return ( +
+ + + this.getAll()} + onChange={e => this.setState({ keyword: e.nativeEvent.text, skipCount: 0 })} + /> + + + + +
+ maxResultCount + skipCount * maxResultCount < + (users === undefined ? 0 : users.totalCount) && ( + + ) + } + keyExtractor={(x, i) => i.toString()} + onEndReachedThreshold={0} + showsVerticalScrollIndicator={false} + refreshControl={ + this.handleReflesh()} + /> + } + data={users === undefined ? [] : users.items} renderItem={data => ( {data.item.userName} )} - renderHiddenItem={(data) => ( + renderHiddenItem={data => ( - )} @@ -77,7 +167,7 @@ class Users extends Component { position="bottomRight" onPress={() => this.props.navigation.navigate('CreateOrEditUser', { - id: "1", + id: "", }) } > @@ -109,21 +199,21 @@ const styles = StyleSheet.create({ backgroundColor: "#303F9F", margin: 0, borderRadius: 0, - justifyContent: "center" + justifyContent: "center", }, rowBackRight: { width: 75, backgroundColor: "#d32f2f", margin: 0, borderRadius: 0, - justifyContent: "center" + justifyContent: "center", }, editIcon: { color: "#fff", }, trashIcon: { color: "#fff", - } + }, }); export default Users; diff --git a/react-native/src/services/httpService.ts b/react-native/src/services/httpService.ts index db8b2e798..bf897d2e7 100644 --- a/react-native/src/services/httpService.ts +++ b/react-native/src/services/httpService.ts @@ -32,12 +32,12 @@ http.interceptors.request.use( // if (!!abp.auth.getToken()) { config.headers.common.Authorization = - 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjEiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiYWRtaW4iLCJBc3BOZXQuSWRlbnRpdHkuU2VjdXJpdHlTdGFtcCI6ImM1ZTFkMjViLWU1MmItNWQ5Zi1kMDYwLTM5ZjJkZjE2ZmNmZSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6IkFkbWluIiwic3ViIjoiMSIsImp0aSI6IjllNWZiNWU5LWNiYjctNGI2Ny04YTBjLTZkYjRhYzJjNWQzMyIsImlhdCI6MTU4MjExNTYzOSwibmJmIjoxNTgyMTE1NjM5LCJleHAiOjE1ODIyMDIwMzksImlzcyI6IlRlbXBsYXRlRGVtbyIsImF1ZCI6IlRlbXBsYXRlRGVtbyJ9.u1Ud53WWlPnf6oi4nIknHpgh1zjLyn35fNYJO2pHp_c '; + 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjUiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoic2FtZXQiLCJBc3BOZXQuSWRlbnRpdHkuU2VjdXJpdHlTdGFtcCI6IkZXQzI1Wkc0MlhFUlozSTZZQzcySTNFNjJJUzNIV0pNIiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9yb2xlIjpbIkFkbWluIiwidGVzYWQiLCJhc2RhcyJdLCJzdWIiOiI1IiwianRpIjoiNGFjNzZkNjEtZTdhZi00YmU4LTlhZjgtMGE1MzEyZjQ1ODk0IiwiaWF0IjoxNTg0ODExNTIyLCJuYmYiOjE1ODQ4MTE1MjIsImV4cCI6MTU4NDg5NzkyMiwiaXNzIjoiVGVtcGxhdGVEZW1vIiwiYXVkIjoiVGVtcGxhdGVEZW1vIn0.gREMGk-ddlo0y0idDnsiYdkn5E2DAMIUPdusv8KrxMI'; // } // config.headers.common['.AspNetCore.Culture'] = abp.utils.getCookieValue('Abp.Localization.CultureName'); // config.headers.common['Abp.TenantId'] = abp.multiTenancy.getTenantIdCookie(); - config.headers.common['Abp.TenantId'] = 1; + //config.headers.common['Abp.TenantId'] = 1; return config; }, function(error) { diff --git a/react-native/src/services/user/dto/changePasswordInput.ts b/react-native/src/services/user/dto/changePasswordInput.ts new file mode 100644 index 000000000..3abc2c53d --- /dev/null +++ b/react-native/src/services/user/dto/changePasswordInput.ts @@ -0,0 +1,4 @@ +export interface ChangePasswordInput { + currentPassword: string; + newPassword: string; +} diff --git a/react-native/src/services/user/userService.ts b/react-native/src/services/user/userService.ts index 89838a1d3..e2007006d 100644 --- a/react-native/src/services/user/userService.ts +++ b/react-native/src/services/user/userService.ts @@ -6,6 +6,7 @@ import { PagedResultDto } from '../../services/dto/pagedResultDto'; import { PagedUserResultRequestDto } from "./dto/PagedUserResultRequestDto"; import { UpdateUserInput } from './dto/updateUserInput'; import http from '../httpService'; +import { ChangePasswordInput } from './dto/changePasswordInput'; class UserService { public async create(createUserInput: CreateOrUpdateUserInput) { @@ -33,13 +34,25 @@ class UserService { return result.data; } + public async changePassword(changePassword: ChangePasswordInput) { + let result = await http.post( + 'api/services/app/User/ChangeLanguage/ChangePassword', + changePassword, + ); + return result.data; + } + public async get(entityDto: EntityDto): Promise { let result = await http.get('api/services/app/User/Get', { params: entityDto }); return result.data.result; } - public async getAll(pagedFilterAndSortedRequest: PagedUserResultRequestDto): Promise> { - let result = await http.get('api/services/app/User/GetAll', { params: pagedFilterAndSortedRequest }); + public async getAll( + pagedFilterAndSortedRequest: PagedUserResultRequestDto, + ): Promise> { + let result = await http.get('api/services/app/User/GetAll', { + params: pagedFilterAndSortedRequest, + }); return result.data.result; } } diff --git a/react-native/src/stores/accountStore.ts b/react-native/src/stores/accountStore.ts index 3e62f9a3e..5efe8f7ab 100644 --- a/react-native/src/stores/accountStore.ts +++ b/react-native/src/stores/accountStore.ts @@ -4,12 +4,12 @@ import IsTenantAvaibleOutput from '../services/account/dto/isTenantAvailableOutp import accountService from '../services/account/accountService'; class AccountStore { - @observable tenant: IsTenantAvaibleOutput = new IsTenantAvaibleOutput() + @observable tenant: IsTenantAvaibleOutput = new IsTenantAvaibleOutput(); - @action - public isTenantAvailable = async (tenancyName: string) => { - this.tenant = await accountService.isTenantAvailable({ tenancyName: tenancyName }); - } + @action + public isTenantAvailable = async (tenancyName: string) => { + this.tenant = await accountService.isTenantAvailable({ tenancyName: tenancyName }); + }; } export default AccountStore; diff --git a/react-native/src/stores/roleStore.ts b/react-native/src/stores/roleStore.ts index 3c1940669..f966091e0 100644 --- a/react-native/src/stores/roleStore.ts +++ b/react-native/src/stores/roleStore.ts @@ -79,7 +79,14 @@ class RoleStore { @action async getAll(pagedFilterAndSortedRequest: PagedRoleResultRequestDto) { let result = await roleService.getAll(pagedFilterAndSortedRequest); - this.roles = result; + if (pagedFilterAndSortedRequest.skipCount === 0) { + this.roles = result; + } else { + this.roles = { + items: this.roles.items.concat(result.items), + totalCount: result.totalCount, + }; + } } } diff --git a/react-native/src/stores/tenantStore.ts b/react-native/src/stores/tenantStore.ts index 5361428e9..9663d6a25 100644 --- a/react-native/src/stores/tenantStore.ts +++ b/react-native/src/stores/tenantStore.ts @@ -33,7 +33,9 @@ class TenantStore { let result = await tenantService.update(updateTenantInput); this.tenants.items = this.tenants.items.map((x: GetAllTenantOutput) => { - if (x.id === updateTenantInput.id) x = result; + if (x.id === updateTenantInput.id) { + x = result; + } return x; }); } @@ -41,7 +43,9 @@ class TenantStore { @action async delete(entityDto: EntityDto) { await tenantService.delete(entityDto); - this.tenants.items = this.tenants.items.filter((x: GetAllTenantOutput) => x.id !== entityDto.id); + this.tenants.items = this.tenants.items.filter( + (x: GetAllTenantOutput) => x.id !== entityDto.id, + ); } @action @@ -53,7 +57,14 @@ class TenantStore { @action async getAll(pagedFilterAndSortedRequest: PagedTenantResultRequestDto) { let result = await tenantService.getAll(pagedFilterAndSortedRequest); - this.tenants = result; + if (pagedFilterAndSortedRequest.skipCount === 0) { + this.tenants = result; + } else { + this.tenants = { + items: this.tenants.items.concat(result.items), + totalCount: result.totalCount, + }; + } } } diff --git a/react-native/src/stores/userStore.ts b/react-native/src/stores/userStore.ts index 51261a9e7..945814859 100644 --- a/react-native/src/stores/userStore.ts +++ b/react-native/src/stores/userStore.ts @@ -8,10 +8,12 @@ import { PagedResultDto } from '../services/dto/pagedResultDto'; import { PagedUserResultRequestDto } from '../services/user/dto/PagedUserResultRequestDto'; import { UpdateUserInput } from '../services/user/dto/updateUserInput'; import userService from '../services/user/userService'; +import { UserModel } from '../models/Users/UserModel'; +import { ChangePasswordInput } from '../services/user/dto/changePasswordInput'; class UserStore { @observable users: PagedResultDto; - @observable editUser!: CreateOrUpdateUserInput; + @observable editUser: UserModel = new UserModel(); @observable roles: GetRoles[] = []; @action @@ -56,7 +58,7 @@ class UserStore { name: '', surname: '', emailAddress: '', - isActive: false, + isActive: true, roleNames: [], password: '', id: 0, @@ -67,12 +69,20 @@ class UserStore { @action async getAll(pagedFilterAndSortedRequest: PagedUserResultRequestDto) { let result = await userService.getAll(pagedFilterAndSortedRequest); - this.users = result; + if (pagedFilterAndSortedRequest.skipCount === 0) { + this.users = result; + } else { + this.users = { items: this.users.items.concat(result.items), totalCount: result.totalCount }; + } } async changeLanguage(languageName: string) { await userService.changeLanguage({ languageName: languageName }); } + + async changePassword(changePassword: ChangePasswordInput) { + await userService.changePassword(changePassword); + } } export default UserStore; diff --git a/react-native/src/utils/utils.ts b/react-native/src/utils/utils.ts index bdda87c5d..0ae639864 100644 --- a/react-native/src/utils/utils.ts +++ b/react-native/src/utils/utils.ts @@ -1,9 +1,9 @@ -import { Toast } from 'native-base' +import { Toast } from 'native-base'; export const _toast = (message: string, type: any = 'danger') => { - Toast.show({ - text: message, - duration: 2000, - type: type, - }) -} + Toast.show({ + text: message, + duration: 3000, + type: type, + }); +};