# 7-4. Thành phần TransferOwnership

![chuyển quyền sở hữu](https://3008973282-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkfEOJOjY6J46ET30b2XH%2Fuploads%2Fgit-blob-da754a4dfcc2548bbc9846f0fa985b503c598561%2Fklaystagram-transferownership.png?alt=media)

1. Vai trò của thành phần `TransferOwnership`
2. Mã thành phần

   2-1. Kết xuất nút `transferOwnership`

   2-2. Thành phần `TransferOwnership`
3. Tương tác với hợp đồng: phương pháp `transferOwnership`
4. Cập nhật dữ liệu vào cửa hàng: hành động `updateOwnerAddress`

## 1) Vai trò của thành phần `TransferOwnership` <a href="#id-1-transferownership-component-s-role" id="id-1-transferownership-component-s-role"></a>

Chủ sở hữu của ảnh có thể chuyển quyền sở hữu ảnh cho một người dùng khác. Bằng cách gửi giao dịch `transferOwnership`, địa chỉ của chủ sở hữu mới sẽ được lưu vào lịch sử quyền sở hữu. Lịch sử này theo dõi các địa chỉ của chủ sở hữu trong quá khứ.

## 2) Mã thành phần <a href="#id-2-component-code" id="id-2-component-code"></a>

### 2-1) Kết xuất nút `TransferOwnership` <a href="#id-2-1-rendering-transferownership-button" id="id-2-1-rendering-transferownership-button"></a>

Chúng ta sẽ chỉ kết xuất nút `TransferOwnership` trên thành phần `FeedPhoto` khi địa chỉ của chủ sở hữu ảnh khớp với địa chỉ của người dùng đã đăng nhập (tức bạn là chủ sở hữu).

```javascript
// src/components/Feed.js

<div className="FeedPhoto">
  // ...
  {
    userAddress.toUpperCase() === currentOwner.toUpperCase() && (
      <TransferOwnershipButton
        className="FeedPhoto__transferOwnership"
        id={id}
        issueDate={issueDate}
        currentOwner={currentOwner}
      />
    )
  }
  // ...
</div>
```

### 2-2) Thành phần `TransferOwnership` <a href="#id-2-2-transferownership-component" id="id-2-2-transferownership-component"></a>

```javascript
// src/components/TransferOwnership.js

import React, { Component } from 'react'
import { connect } from 'react-redux'
import * as photoActions from 'redux/actions/photos'
import ui from 'utils/ui'
import { isValidAddress } from 'utils/crypto'
import Input from 'components/Input'
import Button from 'components/Button'

import './TransferOwnership.scss'

class TransferOwnership extends Component {
  state = {
    to: null,
    warningMessage: '',
  }

  handleInputChange = (e) => {
    this.setState({
      [e.target.name]: e.target.value,
    })
  }

  handleSubmit = (e) => {
    e.preventDefault()
    const { id, transferOwnership } = this.props
    const { to } = this.state

    if (!isValidAddress(to)) {
      return this.setState({
        warningMessage: '* Địa chỉ ví không hợp lệ',
      })
    }
    transferOwnership(id, to)
    ui.hideModal()
  }

  render() {
    const { id, issueDate, currentOwner } = this.props
    return (
      <div className="TransferOwnership">
        <h3 className="TransferOwnership__copyright">Copyright. {id}</h3>
        <p className="TransferOwnership__issueDate">Issue Date  {issueDate}</p>
        <form className="TransferOwnership__form" onSubmit={this.handleSubmit}>
          <Input
            className="TransferOwnership__from"
            name="from"
            label="Current Owner"
            value={currentOwner}
            readOnly
          />
          <Input
            className="TransferOwnership__to"
            name="cho"
            label="Chủ sở hữu mới"
            onChange={this.handleInputChange}
            placeholder="Chuyển quyền sở hữu cho..."
            err={this.state.warningMessage}
            required
          />
          <Button
            type="submit"
            title="Transfer Ownership"
          />
        </form>
      </div>
    )
  }
}

const mapDispatchToProps = (dispatch) => ({
  transferOwnership: (id, to) => dispatch(photoActions.transferOwnership(id, to)),
})

export default connect(null, mapDispatchToProps)(TransferOwnership)
```

## 3) Tương tác với hợp đồng: phương pháp `transferOwnership` <a href="#id-3-interact-with-contract-transferownership-method" id="id-3-interact-with-contract-transferownership-method"></a>

Chúng ta đã tạo hàm `transferOwnership` trong hợp đồng Klaystagram ở chương [4. Soạn hợp đồng thông minh Klaystagram](https://archive-vn.docs.klaytn.foundation/content/dapp/tutorials/klaystagram/4.-write-klaystagram-smart-contract). Hãy gọi hàm từ ứng dụng.

1. Gọi phương pháp hợp đồng: `transferOwnership`
   * `id:` tokenId của ảnh
   * `to:` Địa chỉ để chuyển quyền sở hữu ảnh
2. Đặt các tùy chọn giao dịch
   * `from`: Một tài khoản gửi giao dịch này và thanh toán phí giao dịch.
   * `gas`: Lượng gas tối đa mà tài khoản `from` sẵn sàng thanh toán cho giao dịch này.
3. Sau khi gửi giao dịch, hiển thị tiến trình cùng vòng đời giao dịch bằng thành phần `Toast`.
4. Nếu giao dịch thành công tiến vào một khối, gọi hàm `updateOwnerAddress` để cập nhật địa chỉ của chủ sở hữu mới vào trang nguồn cấp dữ liệu.

```javascript
// src/redux/actions/photo.js

export const transferOwnership = (tokenId, to) => (dispatch) => {
  // 1. Gọi phương pháp hợp đồng: transferOwnership
  try{
    KlaystagramContract.methods.transferOwnership(tokenId, to).send({

      // 2. Đặt tùy chọn giao dịch
      from: getWallet().address,
      gas: '20000000',
    }, (error, txHash) => {
      if (error) throw error;

      // 3. Sau khi gửi giao dịch,
      //thể hiện tiến trình cùng vòng đời giao dịch bằng thành phần `Toast`.
      ui.showToast({
        trạng thái: 'đang chờ',
        message: `Đang gửi giao dịch... (transferOwnership)`,
        txHash,
      })
    })
      .then((receipt) => {
        ui.showToast({
          trạng thái: receipt.trạng thái ? 'success' : 'fail',
          message: `Đã nhận biên lai! Điều đó nghĩa là giao dịch của bạn
              ở trong khối klaytn (#${receipt.blockNumber}) (transferOwnership)`,
            link: receipt.transactionHash,
          })

          // 4. Nếu giao dịch của bạn thành công tiến vào một khối,
        // gọi hàm `updateOwnerAddress` để cập nhật địa chỉ của chủ sở hữu mới vào trang nguồn cấp dữ liệu.
        dispatch(updateOwnerAddress(tokenId, to))
      })
  } catch (error) {
    ui.showToast({
      trạng thái: 'lỗi',
      message: error.toString(),
    })
  }
}
```

## 4) Cập nhật thông tin vào cửa hàng redux: hành động `updateOwnerAddress` <a href="#id-4-update-information-in-redux-store-updateowneraddress-action" id="id-4-update-information-in-redux-store-updateowneraddress-action"></a>

Sau khi chuyển quyền sở hữu, FeedPhoto cần được kết xuất lại bằng địa chỉ của chủ sở hữu mới.\
Để cập nhật địa chỉ của chủ sở hữu mới, hãy gọi dữ liệu `feed` từ cửa hàng và tìm ảnh có tokenId từ biên lai. Sau đó, đẩy địa chỉ của chủ sở hữu mới lên `ownerHistory` và setFeed của ảnh.

```javascript
const updateOwnerAddress = (tokenId, to) => (dispatch, getState) => {
  const { photos: { feed } } = getState()
  const newFeed = feed.map((photo) => {
    if (photo['id'] !== tokenId) return photo
    photo['ownerHistory'] = [...photo['ownerHistory'], to]
    return photo
  })
  dispatch(setFeed(newFeed))
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://archive-vn.docs.klaytn.foundation/content/dapp/tutorials/klaystagram/7.-feedpage/7-4.-transferownership-component.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
